调整项目结构、尝试支持安卓
This commit is contained in:
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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);
|
||||
Reference in New Issue
Block a user