From b5cdf6133bcf7465c7ffa0aabfe5d7ac54f73728 Mon Sep 17 00:00:00 2001 From: eycorsican Date: Sat, 8 Aug 2020 23:48:00 +0800 Subject: [PATCH] support ios --- Cargo.toml | 6 +- src/async/codec.rs | 190 ++++++++++++------------- src/configuration.rs | 175 ++++++++++++----------- src/device.rs | 104 +++++++------- src/error.rs | 44 +++--- src/lib.rs | 12 +- src/platform/ios/device.rs | 251 +++++++++++++++++++++++++++++++++ src/platform/ios/mod.rs | 30 ++++ src/platform/mod.rs | 59 ++++---- src/platform/posix/sockaddr.rs | 109 +++++++------- 10 files changed, 648 insertions(+), 332 deletions(-) create mode 100644 src/platform/ios/device.rs create mode 100644 src/platform/ios/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 5c733239..2f4a6100 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,14 +14,16 @@ keywords = ["tun", "network", "tunnel", "bindings"] libc = "0.2" thiserror = "1" -[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies] -ioctl = { version = "0.5", package = "ioctl-sys" } +[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "ios"))'.dependencies] mio = { version = "0.6", optional = true } tokio = { version = "0.2", features = ["full"], optional = true } tokio-util = { version = "0.3", features = ["codec"], optional = true } bytes = { version = "0.5", optional = true } byteorder = { version = "1.3", optional = true } +[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies] +ioctl = { version = "0.5", package = "ioctl-sys" } + [dev-dependencies] packet = "0.1" futures = "0.3.1" diff --git a/src/async/codec.rs b/src/async/codec.rs index 3dc27cce..10a0d57d 100644 --- a/src/async/codec.rs +++ b/src/async/codec.rs @@ -21,36 +21,36 @@ use tokio_util::codec::{Decoder, Encoder}; /// A packet protocol IP version #[derive(Debug)] enum PacketProtocol { - IPv4, - IPv6, - Other(u8), + IPv4, + IPv6, + Other(u8), } // Note: the protocol in the packet information header is platform dependent. impl PacketProtocol { - #[cfg(target_os = "linux")] - fn into_pi_field(&self) -> Result { - match self { - PacketProtocol::IPv4 => Ok(libc::ETH_P_IP as u16), - PacketProtocol::IPv6 => Ok(libc::ETH_P_IPV6 as u16), - PacketProtocol::Other(_) => Err(io::Error::new( - io::ErrorKind::Other, - "neither an IPv4 or IPv6 packet", - )), - } - } - - #[cfg(target_os = "macos")] - fn into_pi_field(&self) -> Result { - match self { - PacketProtocol::IPv4 => Ok(libc::PF_INET as u16), - PacketProtocol::IPv6 => Ok(libc::PF_INET6 as u16), - PacketProtocol::Other(_) => Err(io::Error::new( - io::ErrorKind::Other, - "neither an IPv4 or IPv6 packet", - )), - } - } + #[cfg(target_os = "linux")] + fn into_pi_field(&self) -> Result { + match self { + PacketProtocol::IPv4 => Ok(libc::ETH_P_IP as u16), + PacketProtocol::IPv6 => Ok(libc::ETH_P_IPV6 as u16), + PacketProtocol::Other(_) => Err(io::Error::new( + io::ErrorKind::Other, + "neither an IPv4 or IPv6 packet", + )), + } + } + + #[cfg(any(target_os = "macos", target_os = "ios"))] + fn into_pi_field(&self) -> Result { + match self { + PacketProtocol::IPv4 => Ok(libc::PF_INET as u16), + PacketProtocol::IPv6 => Ok(libc::PF_INET6 as u16), + PacketProtocol::Other(_) => Err(io::Error::new( + io::ErrorKind::Other, + "neither an IPv4 or IPv6 packet", + )), + } + } } /// A Tun Packet to be sent or received on the TUN interface. @@ -59,88 +59,88 @@ pub struct TunPacket(PacketProtocol, Bytes); /// Infer the protocol based on the first nibble in the packet buffer. fn infer_proto(buf: &[u8]) -> PacketProtocol { - match buf[0] >> 4 { - 4 => PacketProtocol::IPv4, - 6 => PacketProtocol::IPv6, - p => PacketProtocol::Other(p), - } + match buf[0] >> 4 { + 4 => PacketProtocol::IPv4, + 6 => PacketProtocol::IPv6, + p => PacketProtocol::Other(p), + } } impl TunPacket { - /// Create a new `TunPacket` based on a byte slice. - pub fn new(bytes: Vec) -> TunPacket { - let proto = infer_proto(&bytes); - TunPacket(proto, Bytes::from(bytes)) - } - - /// Return this packet's bytes. - pub fn get_bytes(&self) -> &[u8] { - &self.1 - } + /// Create a new `TunPacket` based on a byte slice. + pub fn new(bytes: Vec) -> TunPacket { + let proto = infer_proto(&bytes); + TunPacket(proto, Bytes::from(bytes)) + } + + /// Return this packet's bytes. + pub fn get_bytes(&self) -> &[u8] { + &self.1 + } } /// A TunPacket Encoder/Decoder. pub struct TunPacketCodec(bool); impl TunPacketCodec { - /// Create a new `TunPacketCodec` specifying whether the underlying - /// tunnel Device has enabled the packet information header. - pub fn new(pi: bool) -> TunPacketCodec { - TunPacketCodec(pi) - } + /// Create a new `TunPacketCodec` specifying whether the underlying + /// tunnel Device has enabled the packet information header. + pub fn new(pi: bool) -> TunPacketCodec { + TunPacketCodec(pi) + } } impl Decoder for TunPacketCodec { - type Item = TunPacket; - type Error = io::Error; - - fn decode(&mut self, buf: &mut BytesMut) -> Result, Self::Error> { - if buf.is_empty() { - return Ok(None); - } - - if self.0 { - // ignore malformed packet - if buf.len() <= 4 { - let _ = buf.split_to(buf.len()); - return Ok(None); - } - } - - let mut buf = buf.split_to(buf.len()); - - // if the packet information is enabled we have to ignore the first 4 bytes - if self.0 { - let _ = buf.split_to(4); - } - - let proto = infer_proto(buf.as_ref()); - Ok(Some(TunPacket(proto, buf.freeze()))) - } + type Item = TunPacket; + type Error = io::Error; + + fn decode(&mut self, buf: &mut BytesMut) -> Result, Self::Error> { + if buf.is_empty() { + return Ok(None); + } + + if self.0 { + // ignore malformed packet + if buf.len() <= 4 { + let _ = buf.split_to(buf.len()); + return Ok(None); + } + } + + let mut buf = buf.split_to(buf.len()); + + // if the packet information is enabled we have to ignore the first 4 bytes + if self.0 { + let _ = buf.split_to(4); + } + + let proto = infer_proto(buf.as_ref()); + Ok(Some(TunPacket(proto, buf.freeze()))) + } } impl Encoder for TunPacketCodec { - type Error = io::Error; - - fn encode(&mut self, item: TunPacket, dst: &mut BytesMut) -> Result<(), Self::Error> { - dst.reserve(item.get_bytes().len() + 4); - match item { - TunPacket(proto, bytes) if self.0 => { - // build the packet information header comprising of 2 u16 - // fields: flags and protocol. - let mut buf = Vec::::with_capacity(4); - - // flags is always 0 - buf.write_u16::(0).unwrap(); - // write the protocol as network byte order - buf.write_u16::(proto.into_pi_field()?) - .unwrap(); - - dst.put_slice(&buf); - dst.put(bytes); - } - TunPacket(_, bytes) => dst.put(bytes), - } - Ok(()) - } + type Error = io::Error; + + fn encode(&mut self, item: TunPacket, dst: &mut BytesMut) -> Result<(), Self::Error> { + dst.reserve(item.get_bytes().len() + 4); + match item { + TunPacket(proto, bytes) if self.0 => { + // build the packet information header comprising of 2 u16 + // fields: flags and protocol. + let mut buf = Vec::::with_capacity(4); + + // flags is always 0 + buf.write_u16::(0).unwrap(); + // write the protocol as network byte order + buf.write_u16::(proto.into_pi_field()?) + .unwrap(); + + dst.put_slice(&buf); + dst.put(bytes); + } + TunPacket(_, bytes) => dst.put(bytes), + } + Ok(()) + } } diff --git a/src/configuration.rs b/src/configuration.rs index f378d5c9..6c6652ce 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -12,7 +12,8 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. -use std::net::{Ipv4Addr}; +use std::net::Ipv4Addr; +use std::os::unix::io::RawFd; use crate::address::IntoAddress; use crate::platform; @@ -20,96 +21,106 @@ use crate::platform; /// TUN interface OSI layer of operation. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Layer { - L2, - L3, + L2, + L3, } impl Default for Layer { - fn default() -> Self { Layer::L3 } + fn default() -> Self { + Layer::L3 + } } /// Configuration builder for a TUN interface. #[derive(Clone, Default, Debug)] pub struct Configuration { - pub(crate) name: Option, - pub(crate) platform: platform::Configuration, - - pub(crate) address: Option, - pub(crate) destination: Option, - pub(crate) broadcast: Option, - pub(crate) netmask: Option, - pub(crate) mtu: Option, - pub(crate) enabled: Option, - pub(crate) layer: Option, - pub(crate) queues: Option, + pub(crate) name: Option, + pub(crate) platform: platform::Configuration, + + pub(crate) address: Option, + pub(crate) destination: Option, + pub(crate) broadcast: Option, + pub(crate) netmask: Option, + pub(crate) mtu: Option, + pub(crate) enabled: Option, + pub(crate) layer: Option, + pub(crate) queues: Option, + pub(crate) raw_fd: Option, } impl Configuration { - /// Access the platform dependant configuration. - pub fn platform(&mut self, f: F) -> &mut Self - where F: FnOnce(&mut platform::Configuration) - { - f(&mut self.platform); - self - } - - /// Set the name. - pub fn name>(&mut self, name: S) -> &mut Self { - self.name = Some(name.as_ref().into()); - self - } - - /// Set the address. - pub fn address(&mut self, value: A) -> &mut Self { - self.address = Some(value.into_address().unwrap()); - self - } - - /// Set the destination address. - pub fn destination(&mut self, value: A) -> &mut Self { - self.destination = Some(value.into_address().unwrap()); - self - } - - /// Set the broadcast address. - pub fn broadcast(&mut self, value: A) -> &mut Self { - self.broadcast = Some(value.into_address().unwrap()); - self - } - - /// Set the netmask. - pub fn netmask(&mut self, value: A) -> &mut Self { - self.netmask = Some(value.into_address().unwrap()); - self - } - - /// Set the MTU. - pub fn mtu(&mut self, value: i32) -> &mut Self { - self.mtu = Some(value); - self - } - - /// Set the interface to be enabled once created. - pub fn up(&mut self) -> &mut Self { - self.enabled = Some(true); - self - } - - /// Set the interface to be disabled once created. - pub fn down(&mut self) -> &mut Self { - self.enabled = Some(false); - self - } - - /// Set the OSI layer of operation. - pub fn layer(&mut self, value: Layer) -> &mut Self { - self.layer = Some(value); - self - } - - /// Set the number of queues. - pub fn queues(&mut self, value: usize) -> &mut Self { - self.queues = Some(value); - self - } + /// Access the platform dependant configuration. + pub fn platform(&mut self, f: F) -> &mut Self + where + F: FnOnce(&mut platform::Configuration), + { + f(&mut self.platform); + self + } + + /// Set the name. + pub fn name>(&mut self, name: S) -> &mut Self { + self.name = Some(name.as_ref().into()); + self + } + + /// Set the address. + pub fn address(&mut self, value: A) -> &mut Self { + self.address = Some(value.into_address().unwrap()); + self + } + + /// Set the destination address. + pub fn destination(&mut self, value: A) -> &mut Self { + self.destination = Some(value.into_address().unwrap()); + self + } + + /// Set the broadcast address. + pub fn broadcast(&mut self, value: A) -> &mut Self { + self.broadcast = Some(value.into_address().unwrap()); + self + } + + /// Set the netmask. + pub fn netmask(&mut self, value: A) -> &mut Self { + self.netmask = Some(value.into_address().unwrap()); + self + } + + /// Set the MTU. + pub fn mtu(&mut self, value: i32) -> &mut Self { + self.mtu = Some(value); + self + } + + /// Set the interface to be enabled once created. + pub fn up(&mut self) -> &mut Self { + self.enabled = Some(true); + self + } + + /// Set the interface to be disabled once created. + pub fn down(&mut self) -> &mut Self { + self.enabled = Some(false); + self + } + + /// Set the OSI layer of operation. + pub fn layer(&mut self, value: Layer) -> &mut Self { + self.layer = Some(value); + self + } + + /// Set the number of queues. + pub fn queues(&mut self, value: usize) -> &mut Self { + self.queues = Some(value); + self + } + + /// Set the raw fd. + pub fn raw_fd(&mut self, fd: RawFd) -> &mut Self { + self.raw_fd = Some(fd); + self + } } diff --git a/src/device.rs b/src/device.rs index 38fb441b..cab84328 100644 --- a/src/device.rs +++ b/src/device.rs @@ -15,81 +15,81 @@ use std::io::{Read, Write}; use std::net::Ipv4Addr; -use crate::error::*; use crate::configuration::Configuration; +use crate::error::*; /// A TUN device. pub trait Device: Read + Write { - type Queue: Read + Write; + type Queue: Read + Write; - /// Reconfigure the device. - fn configure(&mut self, config: &Configuration) -> Result<()> { - if let Some(ip) = config.address { - self.set_address(ip)?; - } + /// Reconfigure the device. + fn configure(&mut self, config: &Configuration) -> Result<()> { + if let Some(ip) = config.address { + self.set_address(ip)?; + } - if let Some(ip) = config.destination { - self.set_destination(ip)?; - } + if let Some(ip) = config.destination { + self.set_destination(ip)?; + } - if let Some(ip) = config.broadcast { - self.set_broadcast(ip)?; - } + if let Some(ip) = config.broadcast { + self.set_broadcast(ip)?; + } - if let Some(ip) = config.netmask { - self.set_netmask(ip)?; - } + if let Some(ip) = config.netmask { + self.set_netmask(ip)?; + } - if let Some(mtu) = config.mtu { - self.set_mtu(mtu)?; - } + if let Some(mtu) = config.mtu { + self.set_mtu(mtu)?; + } - if let Some(enabled) = config.enabled { - self.enabled(enabled)?; - } + if let Some(enabled) = config.enabled { + self.enabled(enabled)?; + } - Ok(()) - } + Ok(()) + } - /// Get the device name. - fn name(&self) -> &str; + /// Get the device name. + fn name(&self) -> &str; - /// Set the device name. - fn set_name(&mut self, name: &str) -> Result<()>; + /// Set the device name. + fn set_name(&mut self, name: &str) -> Result<()>; - /// Turn on or off the interface. - fn enabled(&mut self, value: bool) -> Result<()>; + /// Turn on or off the interface. + fn enabled(&mut self, value: bool) -> Result<()>; - /// Get the address. - fn address(&self) -> Result; + /// Get the address. + fn address(&self) -> Result; - /// Set the address. - fn set_address(&mut self, value: Ipv4Addr) -> Result<()>; + /// Set the address. + fn set_address(&mut self, value: Ipv4Addr) -> Result<()>; - /// Get the destination address. - fn destination(&self) -> Result; + /// Get the destination address. + fn destination(&self) -> Result; - /// Set the destination address. - fn set_destination(&mut self, value: Ipv4Addr) -> Result<()>; + /// Set the destination address. + fn set_destination(&mut self, value: Ipv4Addr) -> Result<()>; - /// Get the broadcast address. - fn broadcast(&self) -> Result; + /// Get the broadcast address. + fn broadcast(&self) -> Result; - /// Set the broadcast address. - fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()>; + /// Set the broadcast address. + fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()>; - /// Get the netmask. - fn netmask(&self) -> Result; + /// Get the netmask. + fn netmask(&self) -> Result; - /// Set the netmask. - fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()>; + /// Set the netmask. + fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()>; - /// Get the MTU. - fn mtu(&self) -> Result; + /// Get the MTU. + fn mtu(&self) -> Result; - /// Set the MTU. - fn set_mtu(&mut self, value: i32) -> Result<()>; + /// Set the MTU. + fn set_mtu(&mut self, value: i32) -> Result<()>; - /// Get a device queue. - fn queue(&mut self, index: usize) -> Option<&mut Self::Queue>; + /// Get a device queue. + fn queue(&mut self, index: usize) -> Option<&mut Self::Queue>; } diff --git a/src/error.rs b/src/error.rs index 7c637ed6..fb419600 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,37 +12,43 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. -use std::{io, ffi, num}; +use std::{ffi, io, num}; use thiserror::Error; #[derive(Error, Debug)] pub enum Error { - #[error("device name too long")] - NameTooLong, + #[error("invalid configuration")] + InvalidConfig, - #[error("invalid device name")] - InvalidName, + #[error("not implementated")] + NotImplemented, - #[error("invalid address")] - InvalidAddress, + #[error("device name too long")] + NameTooLong, - #[error("invalid file descriptor")] - InvalidDescriptor, + #[error("invalid device name")] + InvalidName, - #[error("unsuported network layer of operation")] - UnsupportedLayer, + #[error("invalid address")] + InvalidAddress, - #[error("invalid queues number")] - InvalidQueuesNumber, + #[error("invalid file descriptor")] + InvalidDescriptor, - #[error(transparent)] - Io(#[from] io::Error), + #[error("unsuported network layer of operation")] + UnsupportedLayer, - #[error(transparent)] - Nul(#[from] ffi::NulError), + #[error("invalid queues number")] + InvalidQueuesNumber, - #[error(transparent)] - ParseNum(#[from] num::ParseIntError), + #[error(transparent)] + Io(#[from] io::Error), + + #[error(transparent)] + Nul(#[from] ffi::NulError), + + #[error(transparent)] + ParseNum(#[from] num::ParseIntError), } pub type Result = ::std::result::Result; diff --git a/src/lib.rs b/src/lib.rs index c2184110..cb8b78b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,11 +27,17 @@ pub use crate::configuration::{Configuration, Layer}; pub mod platform; pub use crate::platform::create; -#[cfg(all(feature = "async", any(target_os = "linux", target_os = "macos")))] +#[cfg(all( + feature = "async", + any(target_os = "linux", target_os = "macos", target_os = "ios") +))] pub mod r#async; -#[cfg(all(feature = "async", any(target_os = "linux", target_os = "macos")))] +#[cfg(all( + feature = "async", + any(target_os = "linux", target_os = "macos", target_os = "ios") +))] pub use r#async::*; pub fn configure() -> Configuration { - Configuration::default() + Configuration::default() } diff --git a/src/platform/ios/device.rs b/src/platform/ios/device.rs new file mode 100644 index 00000000..300ae9c2 --- /dev/null +++ b/src/platform/ios/device.rs @@ -0,0 +1,251 @@ +// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +// Version 2, December 2004 +// +// Copyleft (ↄ) meh. | http://meh.schizofreni.co +// +// Everyone is permitted to copy and distribute verbatim or modified +// copies of this license document, and changing it is allowed as long +// as the name is changed. +// +// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +// +// 0. You just DO WHAT THE FUCK YOU WANT TO. +#![allow(unused_variables)] + +use std::ffi::CStr; +use std::io::{self, Read, Write}; +use std::mem; +use std::net::Ipv4Addr; +use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; +use std::ptr; +use std::sync::Arc; + +use crate::configuration::{Configuration, Layer}; +use crate::device::Device as D; +use crate::error::*; +use crate::platform::posix::{self, Fd, SockAddr}; + +/// A TUN device using the TUN macOS driver. +pub struct Device { + queue: Queue, +} + +impl Device { + /// Create a new `Device` for the given `Configuration`. + pub fn new(config: &Configuration) -> Result { + let fd = match config.raw_fd { + Some(raw_fd) => raw_fd, + _ => return Err(Error::InvalidConfig), + }; + let mut device = unsafe { + let tun = Fd::new(fd).map_err(|_| io::Error::last_os_error())?; + + Device { + queue: Queue { tun: tun }, + } + }; + Ok(device) + } + + /// Split the interface into a `Reader` and `Writer`. + pub fn split(self) -> (posix::Reader, posix::Writer) { + let fd = Arc::new(self.queue.tun); + (posix::Reader(fd.clone()), posix::Writer(fd.clone())) + } + + /// Return whether the device has packet information + pub fn has_packet_information(&self) -> bool { + self.queue.has_packet_information() + } + + #[cfg(feature = "mio")] + pub fn set_nonblock(&self) -> io::Result<()> { + self.queue.set_nonblock() + } +} + +impl Read for Device { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.queue.tun.read(buf) + } +} + +impl Write for Device { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.queue.tun.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.queue.tun.flush() + } +} + +impl D for Device { + type Queue = Queue; + + fn name(&self) -> &str { + return "not implemented"; + } + + // XXX: Cannot set interface name on Darwin. + fn set_name(&mut self, value: &str) -> Result<()> { + Err(Error::NotImplemented) + } + + fn enabled(&mut self, value: bool) -> Result<()> { + // Err(Error::NotImplemented) + Ok(()) + } + + fn address(&self) -> Result { + Err(Error::NotImplemented) + } + + fn set_address(&mut self, value: Ipv4Addr) -> Result<()> { + Ok(()) + } + + fn destination(&self) -> Result { + Err(Error::NotImplemented) + } + + fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> { + Ok(()) + } + + fn broadcast(&self) -> Result { + Err(Error::NotImplemented) + } + + fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> { + Ok(()) + } + + fn netmask(&self) -> Result { + Err(Error::NotImplemented) + } + + fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> { + Ok(()) + } + + fn mtu(&self) -> Result { + Err(Error::NotImplemented) + } + + fn set_mtu(&mut self, value: i32) -> Result<()> { + Ok(()) + } + + fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> { + if index > 0 { + return None; + } + + Some(&mut self.queue) + } +} + +impl AsRawFd for Device { + fn as_raw_fd(&self) -> RawFd { + self.queue.tun.as_raw_fd() + } +} + +impl IntoRawFd for Device { + fn into_raw_fd(self) -> RawFd { + self.queue.tun.into_raw_fd() + } +} + +pub struct Queue { + tun: Fd, +} + +impl Queue { + pub fn has_packet_information(&self) -> bool { + // on ios this is always the case + true + } + + #[cfg(feature = "mio")] + pub fn set_nonblock(&self) -> io::Result<()> { + self.tun.set_nonblock() + } +} + +impl Read for Queue { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.tun.read(buf) + } +} + +impl Write for Queue { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.tun.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.tun.flush() + } +} + +#[cfg(feature = "mio")] +mod mio { + use mio::event::Evented; + use mio::{Poll, PollOpt, Ready, Token}; + use std::io; + + impl Evented for super::Device { + fn register( + &self, + poll: &Poll, + token: Token, + interest: Ready, + opts: PollOpt, + ) -> io::Result<()> { + self.queue.register(poll, token, interest, opts) + } + + fn reregister( + &self, + poll: &Poll, + token: Token, + interest: Ready, + opts: PollOpt, + ) -> io::Result<()> { + self.queue.reregister(poll, token, interest, opts) + } + + fn deregister(&self, poll: &Poll) -> io::Result<()> { + self.queue.deregister(poll) + } + } + + impl Evented for super::Queue { + fn register( + &self, + poll: &Poll, + token: Token, + interest: Ready, + opts: PollOpt, + ) -> io::Result<()> { + self.tun.register(poll, token, interest, opts) + } + + fn reregister( + &self, + poll: &Poll, + token: Token, + interest: Ready, + opts: PollOpt, + ) -> io::Result<()> { + self.tun.reregister(poll, token, interest, opts) + } + + fn deregister(&self, poll: &Poll) -> io::Result<()> { + self.tun.deregister(poll) + } + } +} diff --git a/src/platform/ios/mod.rs b/src/platform/ios/mod.rs new file mode 100644 index 00000000..19200bb5 --- /dev/null +++ b/src/platform/ios/mod.rs @@ -0,0 +1,30 @@ +// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +// Version 2, December 2004 +// +// Copyleft (ↄ) meh. | http://meh.schizofreni.co +// +// Everyone is permitted to copy and distribute verbatim or modified +// copies of this license document, and changing it is allowed as long +// as the name is changed. +// +// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +// +// 0. You just DO WHAT THE FUCK YOU WANT TO. + +//! macOS specific functionality. + +mod device; +pub use self::device::{Device, Queue}; + +use crate::configuration::Configuration as C; +use crate::error::*; + +/// macOS-only interface configuration. +#[derive(Copy, Clone, Default, Debug)] +pub struct Configuration {} + +/// Create a TUN device with the given name. +pub fn create(configuration: &C) -> Result { + Device::new(&configuration) +} diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 2db3e51a..6916f809 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -20,35 +20,46 @@ pub mod posix; #[cfg(target_os = "linux")] pub mod linux; #[cfg(target_os = "linux")] -pub use self::linux::{Device, Queue, Configuration, create}; +pub use self::linux::{create, Configuration, Device, Queue}; #[cfg(target_os = "macos")] pub mod macos; #[cfg(target_os = "macos")] -pub use self::macos::{Device, Queue, Configuration, create}; +pub use self::macos::{create, Configuration, Device, Queue}; + +#[cfg(target_os = "ios")] +pub mod ios; +#[cfg(target_os = "ios")] +pub use self::ios::{create, Configuration, Device, Queue}; #[cfg(test)] mod test { - use std::net::Ipv4Addr; - use crate::configuration::Configuration; - use crate::device::Device; - - #[test] - fn create() { - let dev = super::create(Configuration::default() - .name("utun6") - .address("192.168.50.1") - .netmask("255.255.0.0") - .mtu(1400) - .up()).unwrap(); - - assert_eq!("192.168.50.1".parse::().unwrap(), - dev.address().unwrap()); - - assert_eq!("255.255.0.0".parse::().unwrap(), - dev.netmask().unwrap()); - - assert_eq!(1400, - dev.mtu().unwrap()); - } + use crate::configuration::Configuration; + use crate::device::Device; + use std::net::Ipv4Addr; + + #[test] + fn create() { + let dev = super::create( + Configuration::default() + .name("utun6") + .address("192.168.50.1") + .netmask("255.255.0.0") + .mtu(1400) + .up(), + ) + .unwrap(); + + assert_eq!( + "192.168.50.1".parse::().unwrap(), + dev.address().unwrap() + ); + + assert_eq!( + "255.255.0.0".parse::().unwrap(), + dev.netmask().unwrap() + ); + + assert_eq!(1400, dev.mtu().unwrap()); + } } diff --git a/src/platform/posix/sockaddr.rs b/src/platform/posix/sockaddr.rs index b1c926b0..e913f83d 100644 --- a/src/platform/posix/sockaddr.rs +++ b/src/platform/posix/sockaddr.rs @@ -13,16 +13,16 @@ // 0. You just DO WHAT THE FUCK YOU WANT TO. use std::mem; +use std::net::Ipv4Addr; use std::ptr; -use std::net::{Ipv4Addr}; +#[cfg(any(target_os = "macos", target_os = "ios"))] +use libc::{c_uchar, c_uint}; #[cfg(target_os = "linux")] use libc::{c_uint, c_ushort}; -#[cfg(target_os = "macos")] -use libc::{c_uint, c_uchar}; -use libc::{sockaddr, sockaddr_in, in_addr}; use libc::AF_INET as _AF_INET; +use libc::{in_addr, sockaddr, sockaddr_in}; use crate::error::*; @@ -33,70 +33,69 @@ pub struct SockAddr(sockaddr_in); #[cfg(target_os = "linux")] const AF_INET: c_ushort = _AF_INET as c_ushort; -#[cfg(target_os = "macos")] +#[cfg(any(target_os = "macos", target_os = "ios"))] const AF_INET: c_uchar = _AF_INET as c_uchar; impl SockAddr { - /// Create a new `SockAddr` from a generic `sockaddr`. - pub fn new(value: &sockaddr) -> Result { - if value.sa_family != AF_INET { - return Err(Error::InvalidAddress); - } - - unsafe { Self::unchecked(value) } - } - - /// Create a new `SockAddr` and not check the source. - pub unsafe fn unchecked(value: &sockaddr) -> Result { - Ok(SockAddr(ptr::read(value as *const _ as *const _))) - } - - /// Get a generic pointer to the `SockAddr`. - pub unsafe fn as_ptr(&self) -> *const sockaddr { - &self.0 as *const _ as *const sockaddr - } + /// Create a new `SockAddr` from a generic `sockaddr`. + pub fn new(value: &sockaddr) -> Result { + if value.sa_family != AF_INET { + return Err(Error::InvalidAddress); + } + + unsafe { Self::unchecked(value) } + } + + /// Create a new `SockAddr` and not check the source. + pub unsafe fn unchecked(value: &sockaddr) -> Result { + Ok(SockAddr(ptr::read(value as *const _ as *const _))) + } + + /// Get a generic pointer to the `SockAddr`. + pub unsafe fn as_ptr(&self) -> *const sockaddr { + &self.0 as *const _ as *const sockaddr + } } impl From for SockAddr { - fn from(ip: Ipv4Addr) -> SockAddr { - let parts = ip.octets(); - let mut addr = unsafe { mem::zeroed::() }; - - addr.sin_family = AF_INET; - addr.sin_port = 0; - addr.sin_addr = in_addr { s_addr: - ((parts[3] as c_uint) << 24) | - ((parts[2] as c_uint) << 16) | - ((parts[1] as c_uint) << 8) | - ((parts[0] as c_uint)) - }; - - SockAddr(addr) - } + fn from(ip: Ipv4Addr) -> SockAddr { + let parts = ip.octets(); + let mut addr = unsafe { mem::zeroed::() }; + + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr = in_addr { + s_addr: ((parts[3] as c_uint) << 24) + | ((parts[2] as c_uint) << 16) + | ((parts[1] as c_uint) << 8) + | (parts[0] as c_uint), + }; + + SockAddr(addr) + } } impl Into for SockAddr { - fn into(self) -> Ipv4Addr { - let ip = self.0.sin_addr.s_addr; - - Ipv4Addr::new( - ((ip ) & 0xff) as u8, - ((ip >> 8) & 0xff) as u8, - ((ip >> 16) & 0xff) as u8, - ((ip >> 24) & 0xff) as u8) - } + fn into(self) -> Ipv4Addr { + let ip = self.0.sin_addr.s_addr; + + Ipv4Addr::new( + ((ip) & 0xff) as u8, + ((ip >> 8) & 0xff) as u8, + ((ip >> 16) & 0xff) as u8, + ((ip >> 24) & 0xff) as u8, + ) + } } impl Into for SockAddr { - fn into(self) -> sockaddr { - unsafe { - mem::transmute(self.0) - } - } + fn into(self) -> sockaddr { + unsafe { mem::transmute(self.0) } + } } impl Into for SockAddr { - fn into(self) -> sockaddr_in { - self.0 - } + fn into(self) -> sockaddr_in { + self.0 + } }