调整项目结构、尝试支持安卓

This commit is contained in:
lubeilin
2023-01-08 15:38:45 +08:00
parent d956e493af
commit 292893e9dd
76 changed files with 1132 additions and 588 deletions
@@ -0,0 +1,214 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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::io::{self, Read, Write};
use std::net::Ipv4Addr;
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use std::sync::Arc;
use crate::configuration::Configuration;
use crate::device::Device as D;
use crate::error::*;
use crate::platform::posix::{self, Fd};
/// A TUN device for Android.
pub struct Device {
queue: Queue,
}
impl Device {
/// Create a new `Device` for the given `Configuration`.
pub fn new(config: &Configuration) -> Result<Self> {
let fd = match config.raw_fd {
Some(raw_fd) => raw_fd,
_ => return Err(Error::InvalidConfig),
};
let device = {
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()
}
/// Set non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
self.queue.set_nonblock()
}
}
impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.queue.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.queue.tun.read_vectored(bufs)
}
}
impl Write for Device {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.queue.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.queue.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.queue.tun.write_vectored(bufs)
}
}
impl D for Device {
type Queue = Queue;
fn name(&self) -> &str {
return "";
}
fn set_name(&mut self, value: &str) -> Result<()> {
Err(Error::NotImplemented)
}
fn enabled(&mut self, value: bool) -> Result<()> {
Ok(())
}
fn address(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn destination(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn broadcast(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn netmask(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn mtu(&self) -> Result<i32> {
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.as_raw_fd()
}
}
impl IntoRawFd for Device {
fn into_raw_fd(self) -> RawFd {
self.queue.into_raw_fd()
}
}
pub struct Queue {
tun: Fd,
}
impl Queue {
pub fn has_packet_information(&self) -> bool {
// on Android this is always the case
false
}
pub fn set_nonblock(&self) -> io::Result<()> {
self.tun.set_nonblock()
}
}
impl AsRawFd for Queue {
fn as_raw_fd(&self) -> RawFd {
self.tun.as_raw_fd()
}
}
impl IntoRawFd for Queue {
fn into_raw_fd(self) -> RawFd {
self.tun.into_raw_fd()
}
}
impl Read for Queue {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.tun.read_vectored(bufs)
}
}
impl Write for Queue {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.tun.write_vectored(bufs)
}
}
@@ -0,0 +1,30 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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.
//! Android specific functionality.
mod device;
pub use self::device::{Device, Queue};
use crate::configuration::Configuration as C;
use crate::error::*;
/// Android-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> {
Device::new(&configuration)
}
+214
View File
@@ -0,0 +1,214 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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::io::{self, Read, Write};
use std::net::Ipv4Addr;
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use std::sync::Arc;
use crate::configuration::Configuration;
use crate::device::Device as D;
use crate::error::*;
use crate::platform::posix::{self, Fd};
/// A TUN device for iOS.
pub struct Device {
queue: Queue,
}
impl Device {
/// Create a new `Device` for the given `Configuration`.
pub fn new(config: &Configuration) -> Result<Self> {
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()
}
/// Set non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
self.queue.set_nonblock()
}
}
impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.queue.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.queue.tun.read_vectored(bufs)
}
}
impl Write for Device {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.queue.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.queue.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.queue.tun.write_vectored(bufs)
}
}
impl D for Device {
type Queue = Queue;
fn name(&self) -> &str {
return "";
}
fn set_name(&mut self, value: &str) -> Result<()> {
Err(Error::NotImplemented)
}
fn enabled(&mut self, value: bool) -> Result<()> {
Ok(())
}
fn address(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn destination(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn broadcast(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn netmask(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn mtu(&self) -> Result<i32> {
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.as_raw_fd()
}
}
impl IntoRawFd for Device {
fn into_raw_fd(self) -> RawFd {
self.queue.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
}
pub fn set_nonblock(&self) -> io::Result<()> {
self.tun.set_nonblock()
}
}
impl AsRawFd for Queue {
fn as_raw_fd(&self) -> RawFd {
self.tun.as_raw_fd()
}
}
impl IntoRawFd for Queue {
fn into_raw_fd(self) -> RawFd {
self.tun.into_raw_fd()
}
}
impl Read for Queue {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.tun.read_vectored(bufs)
}
}
impl Write for Queue {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.tun.write_vectored(bufs)
}
}
+30
View File
@@ -0,0 +1,30 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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.
//! iOS specific functionality.
mod device;
pub use self::device::{Device, Queue};
use crate::configuration::Configuration as C;
use crate::error::*;
/// iOS-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> {
Device::new(&configuration)
}
@@ -0,0 +1,457 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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.
use std::ffi::{CStr, CString};
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 std::vec::Vec;
use libc;
use libc::{c_char, c_short};
use libc::{AF_INET, O_RDWR, SOCK_DGRAM};
use crate::configuration::{Configuration, Layer};
use crate::device::Device as D;
use crate::error::*;
use crate::platform::linux::sys::*;
use crate::platform::posix::{self, Fd, SockAddr};
/// A TUN device using the TUN/TAP Linux driver.
pub struct Device {
name: String,
queues: Vec<Queue>,
ctl: Fd,
}
impl Device {
/// Create a new `Device` for the given `Configuration`.
pub fn new(config: &Configuration) -> Result<Self> {
let mut device = unsafe {
let dev = match config.name.as_ref() {
Some(name) => {
let name = CString::new(name.clone())?;
if name.as_bytes_with_nul().len() > IFNAMSIZ {
return Err(Error::NameTooLong);
}
Some(name)
}
None => None,
};
let mut queues = Vec::new();
let mut req: ifreq = mem::zeroed();
if let Some(dev) = dev.as_ref() {
ptr::copy_nonoverlapping(
dev.as_ptr() as *const c_char,
req.ifrn.name.as_mut_ptr(),
dev.as_bytes().len(),
);
}
let device_type: c_short = config.layer.unwrap_or(Layer::L3).into();
let queues_num = config.queues.unwrap_or(1);
if queues_num < 1 {
return Err(Error::InvalidQueuesNumber);
}
req.ifru.flags = device_type
| if config.platform.packet_information {
0
} else {
IFF_NO_PI
}
| if queues_num > 1 { IFF_MULTI_QUEUE } else { 0 };
for _ in 0..queues_num {
let tun = Fd::new(libc::open(b"/dev/net/tun\0".as_ptr() as *const _, O_RDWR))
.map_err(|_| io::Error::last_os_error())?;
if tunsetiff(tun.0, &mut req as *mut _ as *mut _) < 0 {
return Err(io::Error::last_os_error().into());
}
queues.push(Queue {
tun,
pi_enabled: config.platform.packet_information,
});
}
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))
.map_err(|_| io::Error::last_os_error())?;
Device {
name: CStr::from_ptr(req.ifrn.name.as_ptr())
.to_string_lossy()
.into(),
queues,
ctl,
}
};
device.configure(config)?;
Ok(device)
}
/// Prepare a new request.
unsafe fn request(&self) -> ifreq {
let mut req: ifreq = mem::zeroed();
ptr::copy_nonoverlapping(
self.name.as_ptr() as *const c_char,
req.ifrn.name.as_mut_ptr(),
self.name.len(),
);
req
}
/// Make the device persistent.
pub fn persist(&mut self) -> Result<()> {
unsafe {
if tunsetpersist(self.as_raw_fd(), &1) < 0 {
Err(io::Error::last_os_error().into())
} else {
Ok(())
}
}
}
/// Set the owner of the device.
pub fn user(&mut self, value: i32) -> Result<()> {
unsafe {
if tunsetowner(self.as_raw_fd(), &value) < 0 {
Err(io::Error::last_os_error().into())
} else {
Ok(())
}
}
}
/// Set the group of the device.
pub fn group(&mut self, value: i32) -> Result<()> {
unsafe {
if tunsetgroup(self.as_raw_fd(), &value) < 0 {
Err(io::Error::last_os_error().into())
} else {
Ok(())
}
}
}
pub fn split(mut self) -> (posix::Reader, posix::Writer) {
let queue = self.queues.swap_remove(0);
let fd = Arc::new(queue.tun);
(posix::Reader(fd.clone()), posix::Writer(fd.clone()))
}
/// Return whether the device has packet information
pub fn has_packet_information(&mut self) -> bool {
self.queues[0].has_packet_information()
}
/// Set non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
self.queues[0].set_nonblock()
}
}
impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.queues[0].read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.queues[0].read_vectored(bufs)
}
}
impl Write for Device {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.queues[0].write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.queues[0].flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.queues[0].write_vectored(bufs)
}
}
impl D for Device {
type Queue = Queue;
fn name(&self) -> &str {
&self.name
}
fn set_name(&mut self, value: &str) -> Result<()> {
unsafe {
let name = CString::new(value)?;
if name.as_bytes_with_nul().len() > IFNAMSIZ {
return Err(Error::NameTooLong);
}
let mut req = self.request();
ptr::copy_nonoverlapping(
name.as_ptr() as *const c_char,
req.ifru.newname.as_mut_ptr(),
value.len(),
);
if siocsifname(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
self.name = value.into();
Ok(())
}
}
fn enabled(&mut self, value: bool) -> Result<()> {
unsafe {
let mut req = self.request();
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
if value {
req.ifru.flags |= IFF_UP | IFF_RUNNING;
} else {
req.ifru.flags &= !IFF_UP;
}
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn address(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.addr).map(Into::into)
}
}
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.addr = SockAddr::from(value).into();
if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn destination(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.dstaddr).map(Into::into)
}
}
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.dstaddr = SockAddr::from(value).into();
if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn broadcast(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.broadaddr).map(Into::into)
}
}
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.broadaddr = SockAddr::from(value).into();
if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn netmask(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.netmask).map(Into::into)
}
}
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.netmask = SockAddr::from(value).into();
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn mtu(&self) -> Result<i32> {
unsafe {
let mut req = self.request();
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(req.ifru.mtu)
}
}
fn set_mtu(&mut self, value: i32) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.mtu = value;
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
self.queues.get_mut(index)
}
}
impl AsRawFd for Device {
fn as_raw_fd(&self) -> RawFd {
self.queues[0].as_raw_fd()
}
}
impl IntoRawFd for Device {
fn into_raw_fd(mut self) -> RawFd {
// It is Ok to swap the first queue with the last one, because the self will be dropped afterwards
let queue = self.queues.swap_remove(0);
queue.into_raw_fd()
}
}
pub struct Queue {
tun: Fd,
pi_enabled: bool,
}
impl Queue {
pub fn has_packet_information(&mut self) -> bool {
self.pi_enabled
}
pub fn set_nonblock(&self) -> io::Result<()> {
self.tun.set_nonblock()
}
}
impl Read for Queue {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.tun.read_vectored(bufs)
}
}
impl Write for Queue {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.tun.write_vectored(bufs)
}
}
impl AsRawFd for Queue {
fn as_raw_fd(&self) -> RawFd {
self.tun.as_raw_fd()
}
}
impl IntoRawFd for Queue {
fn into_raw_fd(self) -> RawFd {
self.tun.into_raw_fd()
}
}
impl From<Layer> for c_short {
fn from(layer: Layer) -> Self {
match layer {
Layer::L2 => IFF_TAP,
Layer::L3 => IFF_TUN,
}
}
}
+43
View File
@@ -0,0 +1,43 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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.
//! Linux specific functionality.
pub mod sys;
mod device;
pub use self::device::{Device, Queue};
use crate::configuration::Configuration as C;
use crate::error::*;
/// Linux-only interface configuration.
#[derive(Copy, Clone, Default, Debug)]
pub struct Configuration {
pub(crate) packet_information: bool,
}
impl Configuration {
/// Enable or disable packet information, when enabled the first 4 bytes of
/// each packet is a header with flags and protocol type.
pub fn packet_information(&mut self, value: bool) -> &mut Self {
self.packet_information = value;
self
}
}
/// Create a TUN device with the given name.
pub fn create(configuration: &C) -> Result<Device> {
Device::new(configuration)
}
+111
View File
@@ -0,0 +1,111 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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.
//! Bindings to internal Linux stuff.
use ioctl::*;
use libc::sockaddr;
use libc::{c_char, c_int, c_short, c_uchar, c_uint, c_ulong, c_ushort, c_void};
pub const IFNAMSIZ: usize = 16;
pub const IFF_UP: c_short = 0x1;
pub const IFF_RUNNING: c_short = 0x40;
pub const IFF_TUN: c_short = 0x0001;
pub const IFF_TAP: c_short = 0x0002;
pub const IFF_NO_PI: c_short = 0x1000;
pub const IFF_MULTI_QUEUE: c_short = 0x0100;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifmap {
pub mem_start: c_ulong,
pub mem_end: c_ulong,
pub base_addr: c_ushort,
pub irq: c_uchar,
pub dma: c_uchar,
pub port: c_uchar,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifsu {
pub raw_hdlc_proto: *mut c_void,
pub cisco: *mut c_void,
pub fr: *mut c_void,
pub fr_pvc: *mut c_void,
pub fr_pvc_info: *mut c_void,
pub sync: *mut c_void,
pub te1: *mut c_void,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct if_settings {
pub type_: c_uint,
pub size: c_uint,
pub ifsu: ifsu,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifrn {
pub name: [c_char; IFNAMSIZ],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifru {
pub addr: sockaddr,
pub dstaddr: sockaddr,
pub broadaddr: sockaddr,
pub netmask: sockaddr,
pub hwaddr: sockaddr,
pub flags: c_short,
pub ivalue: c_int,
pub mtu: c_int,
pub map: ifmap,
pub slave: [c_char; IFNAMSIZ],
pub newname: [c_char; IFNAMSIZ],
pub data: *mut c_void,
pub settings: if_settings,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifreq {
pub ifrn: ifrn,
pub ifru: ifru,
}
ioctl!(bad read siocgifflags with 0x8913; ifreq);
ioctl!(bad write siocsifflags with 0x8914; ifreq);
ioctl!(bad read siocgifaddr with 0x8915; ifreq);
ioctl!(bad write siocsifaddr with 0x8916; ifreq);
ioctl!(bad read siocgifdstaddr with 0x8917; ifreq);
ioctl!(bad write siocsifdstaddr with 0x8918; ifreq);
ioctl!(bad read siocgifbrdaddr with 0x8919; ifreq);
ioctl!(bad write siocsifbrdaddr with 0x891a; ifreq);
ioctl!(bad read siocgifnetmask with 0x891b; ifreq);
ioctl!(bad write siocsifnetmask with 0x891c; ifreq);
ioctl!(bad read siocgifmtu with 0x8921; ifreq);
ioctl!(bad write siocsifmtu with 0x8922; ifreq);
ioctl!(bad write siocsifname with 0x8923; ifreq);
ioctl!(write tunsetiff with b'T', 202; c_int);
ioctl!(write tunsetpersist with b'T', 203; c_int);
ioctl!(write tunsetowner with b'T', 204; c_int);
ioctl!(write tunsetgroup with b'T', 206; c_int);
@@ -0,0 +1,438 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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 libc;
use libc::{c_char, c_uint, c_void, sockaddr, socklen_t, AF_INET, SOCK_DGRAM};
use crate::configuration::{Configuration, Layer};
use crate::device::Device as D;
use crate::error::*;
use crate::platform::macos::sys::*;
use crate::platform::posix::{self, Fd, SockAddr};
/// A TUN device using the TUN macOS driver.
pub struct Device {
name: String,
queue: Queue,
ctl: Fd,
}
impl Device {
/// Create a new `Device` for the given `Configuration`.
pub fn new(config: &Configuration) -> Result<Self> {
let id = if let Some(name) = config.name.as_ref() {
if name.len() > IFNAMSIZ {
return Err(Error::NameTooLong);
}
if !name.starts_with("utun") {
return Err(Error::InvalidName);
}
name[4..].parse()?
} else {
0
};
if config.layer.filter(|l| *l != Layer::L3).is_some() {
return Err(Error::UnsupportedLayer);
}
let queues_number = config.queues.unwrap_or(1);
if queues_number != 1 {
return Err(Error::InvalidQueuesNumber);
}
let mut device = unsafe {
let tun = Fd::new(libc::socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL))
.map_err(|_| io::Error::last_os_error())?;
let mut info = ctl_info {
ctl_id: 0,
ctl_name: {
let mut buffer = [0; 96];
for (i, o) in UTUN_CONTROL_NAME.as_bytes().iter().zip(buffer.iter_mut()) {
*o = *i as _;
}
buffer
},
};
if ctliocginfo(tun.0, &mut info as *mut _ as *mut _) < 0 {
return Err(io::Error::last_os_error().into());
}
let addr = sockaddr_ctl {
sc_id: info.ctl_id,
sc_len: mem::size_of::<sockaddr_ctl>() as _,
sc_family: AF_SYSTEM,
ss_sysaddr: AF_SYS_CONTROL,
sc_unit: id as c_uint,
sc_reserved: [0; 5],
};
if libc::connect(
tun.0,
&addr as *const sockaddr_ctl as *const sockaddr,
mem::size_of_val(&addr) as socklen_t,
) < 0
{
return Err(io::Error::last_os_error().into());
}
let mut name = [0u8; 64];
let mut name_len: socklen_t = 64;
if libc::getsockopt(
tun.0,
SYSPROTO_CONTROL,
UTUN_OPT_IFNAME,
&mut name as *mut _ as *mut c_void,
&mut name_len as *mut socklen_t,
) < 0
{
return Err(io::Error::last_os_error().into());
}
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))
.map_err(|_| io::Error::last_os_error())?;
Device {
name: CStr::from_ptr(name.as_ptr() as *const c_char)
.to_string_lossy()
.into(),
queue: Queue { tun: tun },
ctl: ctl,
}
};
device.configure(&config)?;
Ok(device)
}
/// Prepare a new request.
pub unsafe fn request(&self) -> ifreq {
let mut req: ifreq = mem::zeroed();
ptr::copy_nonoverlapping(
self.name.as_ptr() as *const c_char,
req.ifrn.name.as_mut_ptr(),
self.name.len(),
);
req
}
/// Set the IPv4 alias of the device.
pub fn set_alias(&mut self, addr: Ipv4Addr, broadaddr: Ipv4Addr, mask: Ipv4Addr) -> Result<()> {
unsafe {
let mut req: ifaliasreq = mem::zeroed();
ptr::copy_nonoverlapping(
self.name.as_ptr() as *const c_char,
req.ifran.as_mut_ptr(),
self.name.len(),
);
req.addr = SockAddr::from(addr).into();
req.broadaddr = SockAddr::from(broadaddr).into();
req.mask = SockAddr::from(mask).into();
if siocaifaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
/// 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()
}
/// Set non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
self.queue.set_nonblock()
}
}
impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.queue.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.queue.tun.read_vectored(bufs)
}
}
impl Write for Device {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.queue.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.queue.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.queue.tun.write_vectored(bufs)
}
}
impl D for Device {
type Queue = Queue;
fn name(&self) -> &str {
&self.name
}
// XXX: Cannot set interface name on Darwin.
fn set_name(&mut self, value: &str) -> Result<()> {
Err(Error::InvalidName)
}
fn enabled(&mut self, value: bool) -> Result<()> {
unsafe {
let mut req = self.request();
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
if value {
req.ifru.flags |= IFF_UP | IFF_RUNNING;
} else {
req.ifru.flags &= !IFF_UP;
}
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn address(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.addr).map(Into::into)
}
}
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.addr = SockAddr::from(value).into();
if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn destination(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.dstaddr).map(Into::into)
}
}
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.dstaddr = SockAddr::from(value).into();
if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn broadcast(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.broadaddr).map(Into::into)
}
}
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.broadaddr = SockAddr::from(value).into();
if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn netmask(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::unchecked(&req.ifru.addr).map(Into::into)
}
}
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.addr = SockAddr::from(value).into();
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn mtu(&self) -> Result<i32> {
unsafe {
let mut req = self.request();
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(req.ifru.mtu)
}
}
fn set_mtu(&mut self, value: i32) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.mtu = value;
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
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.as_raw_fd()
}
}
impl IntoRawFd for Device {
fn into_raw_fd(self) -> RawFd {
self.queue.into_raw_fd()
}
}
pub struct Queue {
tun: Fd,
}
impl Queue {
pub fn has_packet_information(&self) -> bool {
// on macos this is always the case
true
}
pub fn set_nonblock(&self) -> io::Result<()> {
self.tun.set_nonblock()
}
}
impl AsRawFd for Queue {
fn as_raw_fd(&self) -> RawFd {
self.tun.as_raw_fd()
}
}
impl IntoRawFd for Queue {
fn into_raw_fd(self) -> RawFd {
self.tun.into_raw_fd()
}
}
impl Read for Queue {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.tun.read_vectored(bufs)
}
}
impl Write for Queue {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.tun.write_vectored(bufs)
}
}
+32
View File
@@ -0,0 +1,32 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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.
pub mod sys;
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> {
Device::new(&configuration)
}
+138
View File
@@ -0,0 +1,138 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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.
//! Bindings to internal macOS stuff.
use ioctl::*;
use libc::sockaddr;
use libc::{c_char, c_int, c_short, c_uint, c_ushort, c_void};
pub const IFNAMSIZ: usize = 16;
pub const IFF_UP: c_short = 0x1;
pub const IFF_RUNNING: c_short = 0x40;
pub const AF_SYS_CONTROL: c_ushort = 2;
pub const AF_SYSTEM: c_char = 32;
pub const PF_SYSTEM: c_int = AF_SYSTEM as c_int;
pub const SYSPROTO_CONTROL: c_int = 2;
pub const UTUN_OPT_IFNAME: c_int = 2;
pub const UTUN_CONTROL_NAME: &str = "com.apple.net.utun_control";
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ctl_info {
pub ctl_id: c_uint,
pub ctl_name: [c_char; 96],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct sockaddr_ctl {
pub sc_len: c_char,
pub sc_family: c_char,
pub ss_sysaddr: c_ushort,
pub sc_id: c_uint,
pub sc_unit: c_uint,
pub sc_reserved: [c_uint; 5],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifrn {
pub name: [c_char; IFNAMSIZ],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifdevmtu {
pub current: c_int,
pub min: c_int,
pub max: c_int,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifku {
pub ptr: *mut c_void,
pub value: c_int,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifkpi {
pub module_id: c_uint,
pub type_: c_uint,
pub ifku: ifku,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifru {
pub addr: sockaddr,
pub dstaddr: sockaddr,
pub broadaddr: sockaddr,
pub flags: c_short,
pub metric: c_int,
pub mtu: c_int,
pub phys: c_int,
pub media: c_int,
pub intval: c_int,
pub data: *mut c_void,
pub devmtu: ifdevmtu,
pub wake_flags: c_uint,
pub route_refcnt: c_uint,
pub cap: [c_int; 2],
pub functional_type: c_uint,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifreq {
pub ifrn: ifrn,
pub ifru: ifru,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifaliasreq {
pub ifran: [c_char; IFNAMSIZ],
pub addr: sockaddr,
pub broadaddr: sockaddr,
pub mask: sockaddr,
}
ioctl!(readwrite ctliocginfo with 'N', 3; ctl_info);
ioctl!(write siocsifflags with 'i', 16; ifreq);
ioctl!(readwrite siocgifflags with 'i', 17; ifreq);
ioctl!(write siocsifaddr with 'i', 12; ifreq);
ioctl!(readwrite siocgifaddr with 'i', 33; ifreq);
ioctl!(write siocsifdstaddr with 'i', 14; ifreq);
ioctl!(readwrite siocgifdstaddr with 'i', 34; ifreq);
ioctl!(write siocsifbrdaddr with 'i', 19; ifreq);
ioctl!(readwrite siocgifbrdaddr with 'i', 35; ifreq);
ioctl!(write siocsifnetmask with 'i', 22; ifreq);
ioctl!(readwrite siocgifnetmask with 'i', 37; ifreq);
ioctl!(write siocsifmtu with 'i', 52; ifreq);
ioctl!(readwrite siocgifmtu with 'i', 51; ifreq);
ioctl!(write siocaifaddr with 'i', 26; ifaliasreq);
ioctl!(write siocdifaddr with 'i', 25; ifreq);
+70
View File
@@ -0,0 +1,70 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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.
//! Platform specific modules.
#[cfg(unix)]
pub mod posix;
#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "linux")]
pub use self::linux::{create, Configuration, Device, Queue};
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(target_os = "macos")]
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(target_os = "android")]
pub mod android;
#[cfg(target_os = "android")]
pub use self::android::{create, Configuration, Device, Queue};
#[cfg(test)]
mod test {
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::<Ipv4Addr>().unwrap(),
dev.address().unwrap()
);
assert_eq!(
"255.255.0.0".parse::<Ipv4Addr>().unwrap(),
dev.netmask().unwrap()
);
assert_eq!(1400, dev.mtu().unwrap());
}
}
+124
View File
@@ -0,0 +1,124 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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.
use std::io::{self, Read, Write};
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use crate::error::*;
use libc::{self, fcntl, F_GETFL, F_SETFL, O_NONBLOCK};
/// POSIX file descriptor support for `io` traits.
pub struct Fd(pub RawFd);
impl Fd {
pub fn new(value: RawFd) -> Result<Self> {
if value < 0 {
return Err(Error::InvalidDescriptor);
}
Ok(Fd(value))
}
/// Enable non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
match unsafe { fcntl(self.0, F_SETFL, fcntl(self.0, F_GETFL) | O_NONBLOCK) } {
0 => Ok(()),
_ => Err(io::Error::last_os_error()),
}
}
}
impl Read for Fd {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
unsafe {
let amount = libc::read(self.0, buf.as_mut_ptr() as *mut _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
unsafe {
let iov = bufs.as_ptr().cast();
let iovcnt = bufs.len().min(libc::c_int::MAX as usize) as _;
let n = libc::readv(self.0, iov, iovcnt);
if n < 0 {
return Err(io::Error::last_os_error());
}
Ok(n as usize)
}
}
}
impl Write for Fd {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
unsafe {
let amount = libc::write(self.0, buf.as_ptr() as *const _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
unsafe {
let iov = bufs.as_ptr().cast();
let iovcnt = bufs.len().min(libc::c_int::MAX as usize) as _;
let n = libc::writev(self.0, iov, iovcnt);
if n < 0 {
return Err(io::Error::last_os_error());
}
Ok(n as usize)
}
}
}
impl AsRawFd for Fd {
fn as_raw_fd(&self) -> RawFd {
self.0
}
}
impl IntoRawFd for Fd {
fn into_raw_fd(mut self) -> RawFd {
let fd = self.0;
self.0 = -1;
fd
}
}
impl Drop for Fd {
fn drop(&mut self) {
unsafe {
if self.0 >= 0 {
libc::close(self.0);
}
}
}
}
+24
View File
@@ -0,0 +1,24 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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.
//! POSIX compliant support.
mod sockaddr;
pub use self::sockaddr::SockAddr;
mod fd;
pub use self::fd::Fd;
mod split;
pub use self::split::{Reader, Writer};
@@ -0,0 +1,96 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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.
use std::mem;
use std::net::Ipv4Addr;
use std::ptr;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use libc::c_uchar;
#[cfg(any(target_os = "linux", target_os = "android"))]
use libc::c_ushort;
use libc::AF_INET as _AF_INET;
use libc::{in_addr, sockaddr, sockaddr_in};
use crate::error::*;
/// A wrapper for `sockaddr_in`.
#[derive(Copy, Clone)]
pub struct SockAddr(sockaddr_in);
#[cfg(any(target_os = "linux", target_os = "android"))]
const AF_INET: c_ushort = _AF_INET as c_ushort;
#[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<Self> {
if value.sa_family != AF_INET {
return Err(Error::InvalidAddress);
}
unsafe { Self::unchecked(value) }
}
/// # Safety
/// Create a new `SockAddr` and not check the source.
pub unsafe fn unchecked(value: &sockaddr) -> Result<Self> {
Ok(SockAddr(ptr::read(value as *const _ as *const _)))
}
/// # Safety
/// Get a generic pointer to the `SockAddr`.
pub unsafe fn as_ptr(&self) -> *const sockaddr {
&self.0 as *const _ as *const sockaddr
}
}
impl From<Ipv4Addr> for SockAddr {
fn from(ip: Ipv4Addr) -> SockAddr {
let octets = ip.octets();
let mut addr = unsafe { mem::zeroed::<sockaddr_in>() };
addr.sin_family = AF_INET;
addr.sin_port = 0;
addr.sin_addr = in_addr {
s_addr: u32::from_ne_bytes(octets),
};
SockAddr(addr)
}
}
impl From<SockAddr> for Ipv4Addr {
fn from(addr: SockAddr) -> Ipv4Addr {
let ip = addr.0.sin_addr.s_addr;
let [a, b, c, d] = ip.to_ne_bytes();
Ipv4Addr::new(a, b, c, d)
}
}
impl From<SockAddr> for sockaddr {
fn from(addr: SockAddr) -> sockaddr {
unsafe { mem::transmute(addr.0) }
}
}
impl From<SockAddr> for sockaddr_in {
fn from(addr: SockAddr) -> sockaddr_in {
addr.0
}
}
+105
View File
@@ -0,0 +1,105 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | 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.
use std::io::{self, Read, Write};
use std::mem;
use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::Arc;
use crate::platform::posix::Fd;
use libc;
/// Read-only end for a file descriptor.
pub struct Reader(pub(crate) Arc<Fd>);
/// Write-only end for a file descriptor.
pub struct Writer(pub(crate) Arc<Fd>);
impl Read for Reader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
unsafe {
let amount = libc::read(self.0.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
unsafe {
let mut msg: libc::msghdr = mem::zeroed();
// msg.msg_name: NULL
// msg.msg_namelen: 0
msg.msg_iov = bufs.as_mut_ptr().cast();
msg.msg_iovlen = bufs.len().min(libc::c_int::MAX as usize) as _;
let n = libc::recvmsg(self.0.as_raw_fd(), &mut msg, 0);
if n < 0 {
return Err(io::Error::last_os_error());
}
Ok(n as usize)
}
}
}
impl Write for Writer {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
unsafe {
let amount = libc::write(self.0.as_raw_fd(), buf.as_ptr() as *const _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
unsafe {
let mut msg: libc::msghdr = mem::zeroed();
// msg.msg_name = NULL
// msg.msg_namelen = 0
msg.msg_iov = bufs.as_ptr() as *mut _;
msg.msg_iovlen = bufs.len().min(libc::c_int::MAX as usize) as _;
let n = libc::sendmsg(self.0.as_raw_fd(), &msg, 0);
if n < 0 {
return Err(io::Error::last_os_error());
}
Ok(n as usize)
}
}
}
impl AsRawFd for Reader {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
impl AsRawFd for Writer {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}