v1.1
This commit is contained in:
@@ -15,31 +15,11 @@ libc = "0.2"
|
||||
thiserror = "1"
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "android"))'.dependencies]
|
||||
tokio = { version = "1", features = ["net", "macros"], optional = true }
|
||||
tokio-util = { version = "0.6", features = ["codec"], optional = true }
|
||||
bytes = { version = "1", optional = true }
|
||||
byteorder = { version = "1", optional = true }
|
||||
# This is only for the `ready` macro.
|
||||
futures-core = { version = "0.3", optional = true }
|
||||
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
||||
ioctl = { version = "0.6", package = "ioctl-sys" }
|
||||
|
||||
[dev-dependencies]
|
||||
packet = "0.1"
|
||||
futures = "0.3"
|
||||
|
||||
[features]
|
||||
async = ["tokio", "tokio-util", "bytes", "byteorder", "futures-core"]
|
||||
|
||||
[[example]]
|
||||
name = "read-async"
|
||||
required-features = [ "async", "tokio/rt-multi-thread" ]
|
||||
|
||||
[[example]]
|
||||
name = "read-async-codec"
|
||||
required-features = [ "async", "tokio/rt-multi-thread" ]
|
||||
|
||||
[[example]]
|
||||
name = "ping-tun"
|
||||
required-features = [ "async", "tokio/rt-multi-thread" ]
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
TUN interfaces [](https://crates.io/crates/tun)  
|
||||
==============
|
||||
This crate allows the creation and usage of TUN interfaces, the aim is to make this cross-platform.
|
||||
|
||||
Usage
|
||||
-----
|
||||
First, add the following to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
tun = "0.5"
|
||||
```
|
||||
|
||||
Next, add this to your crate root:
|
||||
|
||||
```rust
|
||||
extern crate tun;
|
||||
```
|
||||
|
||||
If you want to use the TUN interface with mio/tokio, you need to enable the `async` feature:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
tun = { version = "0.5", features = ["async"] }
|
||||
```
|
||||
|
||||
Example
|
||||
-------
|
||||
The following example creates and configures a TUN interface and starts reading
|
||||
packets from it.
|
||||
|
||||
```rust
|
||||
use std::io::Read;
|
||||
|
||||
extern crate tun;
|
||||
|
||||
fn main() {
|
||||
let mut config = tun::Configuration::default();
|
||||
config.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.up();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
config.platform(|config| {
|
||||
config.packet_information(true);
|
||||
});
|
||||
|
||||
let mut dev = tun::create(&config).unwrap();
|
||||
let mut buf = [0; 4096];
|
||||
|
||||
loop {
|
||||
let amount = dev.read(&mut buf).unwrap();
|
||||
println!("{:?}", &buf[0 .. amount]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Platforms
|
||||
=========
|
||||
Not every platform is supported.
|
||||
|
||||
Linux
|
||||
-----
|
||||
You will need the `tun` module to be loaded and root is required to create
|
||||
interfaces.
|
||||
|
||||
macOS
|
||||
-----
|
||||
It just werks, but you have to set up routing manually.
|
||||
|
||||
iOS
|
||||
----
|
||||
You can pass the file descriptor of the TUN device to `rust-tun` to create the interface.
|
||||
|
||||
Here is an example to create the TUN device on iOS and pass the `fd` to `rust-tun`:
|
||||
```swift
|
||||
// Swift
|
||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
|
||||
let tunnelNetworkSettings = createTunnelSettings() // Configure TUN address, DNS, mtu, routing...
|
||||
setTunnelNetworkSettings(tunnelNetworkSettings) { [weak self] error in
|
||||
let tunFd = self?.packetFlow.value(forKeyPath: "socket.fileDescriptor") as! Int32
|
||||
DispatchQueue.global(qos: .default).async {
|
||||
start_tun(tunFd)
|
||||
}
|
||||
completionHandler(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```rust
|
||||
#[no_mangle]
|
||||
pub extern "C" fn start_tun(fd: std::os::raw::c_int) {
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let mut cfg = tun::Configuration::default();
|
||||
cfg.raw_fd(fd);
|
||||
let mut tun = tun::create_as_async(&cfg).unwrap();
|
||||
let mut framed = tun.into_framed();
|
||||
while let Some(packet) = framed.next().await {
|
||||
...
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
@@ -1,78 +0,0 @@
|
||||
// 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 futures::{SinkExt, StreamExt};
|
||||
use packet::{builder::Builder, icmp, ip, Packet};
|
||||
use tun::{self, Configuration, TunPacket};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let mut config = Configuration::default();
|
||||
|
||||
config
|
||||
.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.up();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
config.platform(|config| {
|
||||
config.packet_information(true);
|
||||
});
|
||||
|
||||
let dev = tun::create_as_async(&config).unwrap();
|
||||
|
||||
let mut framed = dev.into_framed();
|
||||
|
||||
while let Some(packet) = framed.next().await {
|
||||
match packet {
|
||||
Ok(pkt) => match ip::Packet::new(pkt.get_bytes()) {
|
||||
Ok(ip::Packet::V4(pkt)) => match icmp::Packet::new(pkt.payload()) {
|
||||
Ok(icmp) => match icmp.echo() {
|
||||
Ok(icmp) => {
|
||||
let reply = ip::v4::Builder::default()
|
||||
.id(0x42)
|
||||
.unwrap()
|
||||
.ttl(64)
|
||||
.unwrap()
|
||||
.source(pkt.destination())
|
||||
.unwrap()
|
||||
.destination(pkt.source())
|
||||
.unwrap()
|
||||
.icmp()
|
||||
.unwrap()
|
||||
.echo()
|
||||
.unwrap()
|
||||
.reply()
|
||||
.unwrap()
|
||||
.identifier(icmp.identifier())
|
||||
.unwrap()
|
||||
.sequence(icmp.sequence())
|
||||
.unwrap()
|
||||
.payload(icmp.payload())
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
framed.send(TunPacket::new(reply)).await.unwrap();
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
},
|
||||
Err(err) => println!("Received an invalid packet: {:?}", err),
|
||||
_ => {}
|
||||
},
|
||||
Err(err) => panic!("Error: {:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
// 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 bytes::BytesMut;
|
||||
use futures::StreamExt;
|
||||
use packet::{ip::Packet, Error};
|
||||
use tokio_util::codec::{Decoder, FramedRead};
|
||||
|
||||
pub struct IPPacketCodec;
|
||||
|
||||
impl Decoder for IPPacketCodec {
|
||||
type Item = Packet<BytesMut>;
|
||||
type Error = Error;
|
||||
|
||||
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||
if buf.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let buf = buf.split_to(buf.len());
|
||||
Ok(match Packet::no_payload(buf) {
|
||||
Ok(pkt) => Some(pkt),
|
||||
Err(err) => {
|
||||
println!("error {:?}", err);
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.up();
|
||||
|
||||
let dev = tun::create_as_async(&config).unwrap();
|
||||
|
||||
let mut stream = FramedRead::new(dev, IPPacketCodec);
|
||||
|
||||
while let Some(packet) = stream.next().await {
|
||||
match packet {
|
||||
Ok(pkt) => println!("pkt: {:#?}", pkt),
|
||||
Err(err) => panic!("Error: {:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// 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 futures::StreamExt;
|
||||
use packet::ip::Packet;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.up();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
config.platform(|config| {
|
||||
config.packet_information(true);
|
||||
});
|
||||
|
||||
let dev = tun::create_as_async(&config).unwrap();
|
||||
|
||||
let mut stream = dev.into_framed();
|
||||
|
||||
while let Some(packet) = stream.next().await {
|
||||
match packet {
|
||||
Ok(pkt) => println!("pkt: {:#?}", Packet::unchecked(pkt.get_bytes())),
|
||||
Err(err) => panic!("Error: {:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// 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::Read;
|
||||
|
||||
fn main() {
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.up();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
config.platform(|config| {
|
||||
config.packet_information(true);
|
||||
});
|
||||
|
||||
let mut dev = tun::create(&config).unwrap();
|
||||
let mut buf = [0; 4096];
|
||||
|
||||
loop {
|
||||
let amount = dev.read(&mut buf).unwrap();
|
||||
println!("{:?}", &buf[0..amount]);
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
// 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;
|
||||
|
||||
use byteorder::{NativeEndian, NetworkEndian, WriteBytesExt};
|
||||
use bytes::{BufMut, Bytes, BytesMut};
|
||||
use tokio_util::codec::{Decoder, Encoder};
|
||||
|
||||
/// A packet protocol IP version
|
||||
#[derive(Debug)]
|
||||
enum PacketProtocol {
|
||||
IPv4,
|
||||
IPv6,
|
||||
Other(u8),
|
||||
}
|
||||
|
||||
// Note: the protocol in the packet information header is platform dependent.
|
||||
impl PacketProtocol {
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
fn into_pi_field(&self) -> Result<u16, io::Error> {
|
||||
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<u16, io::Error> {
|
||||
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.
|
||||
#[derive(Debug)]
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
impl TunPacket {
|
||||
/// Create a new `TunPacket` based on a byte slice.
|
||||
pub fn new(bytes: Vec<u8>) -> TunPacket {
|
||||
let proto = infer_proto(&bytes);
|
||||
TunPacket(proto, Bytes::from(bytes))
|
||||
}
|
||||
|
||||
/// Return this packet's bytes.
|
||||
pub fn get_bytes(&self) -> &[u8] {
|
||||
&self.1
|
||||
}
|
||||
|
||||
pub fn into_bytes(self) -> Bytes {
|
||||
self.1
|
||||
}
|
||||
}
|
||||
|
||||
/// A TunPacket Encoder/Decoder.
|
||||
pub struct TunPacketCodec(bool, i32);
|
||||
|
||||
impl TunPacketCodec {
|
||||
/// Create a new `TunPacketCodec` specifying whether the underlying
|
||||
/// tunnel Device has enabled the packet information header.
|
||||
pub fn new(pi: bool, mtu: i32) -> TunPacketCodec {
|
||||
TunPacketCodec(pi, mtu)
|
||||
}
|
||||
}
|
||||
|
||||
impl Decoder for TunPacketCodec {
|
||||
type Item = TunPacket;
|
||||
type Error = io::Error;
|
||||
|
||||
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||
if buf.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut pkt = buf.split_to(buf.len());
|
||||
|
||||
// reserve enough space for the next packet
|
||||
if self.0 {
|
||||
buf.reserve(self.1 as usize + 4);
|
||||
} else {
|
||||
buf.reserve(self.1 as usize);
|
||||
}
|
||||
|
||||
// if the packet information is enabled we have to ignore the first 4 bytes
|
||||
if self.0 {
|
||||
let _ = pkt.split_to(4);
|
||||
}
|
||||
|
||||
let proto = infer_proto(pkt.as_ref());
|
||||
Ok(Some(TunPacket(proto, pkt.freeze())))
|
||||
}
|
||||
}
|
||||
|
||||
impl Encoder<TunPacket> 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::<u8>::with_capacity(4);
|
||||
|
||||
// flags is always 0
|
||||
buf.write_u16::<NativeEndian>(0).unwrap();
|
||||
// write the protocol as network byte order
|
||||
buf.write_u16::<NetworkEndian>(proto.into_pi_field()?)
|
||||
.unwrap();
|
||||
|
||||
dst.put_slice(&buf);
|
||||
dst.put(bytes);
|
||||
}
|
||||
TunPacket(_, bytes) => dst.put(bytes),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
// 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;
|
||||
use std::io::{IoSlice, Read, Write};
|
||||
|
||||
use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
use futures_core::ready;
|
||||
use tokio::io::unix::AsyncFd;
|
||||
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
||||
use tokio_util::codec::Framed;
|
||||
|
||||
use crate::device::Device as D;
|
||||
use crate::platform::{Device, Queue};
|
||||
use crate::r#async::codec::*;
|
||||
|
||||
/// An async TUN device wrapper around a TUN device.
|
||||
pub struct AsyncDevice {
|
||||
inner: AsyncFd<Device>,
|
||||
}
|
||||
|
||||
impl AsyncDevice {
|
||||
/// Create a new `AsyncDevice` wrapping around a `Device`.
|
||||
pub fn new(device: Device) -> io::Result<AsyncDevice> {
|
||||
device.set_nonblock()?;
|
||||
Ok(AsyncDevice {
|
||||
inner: AsyncFd::new(device)?,
|
||||
})
|
||||
}
|
||||
/// Returns a shared reference to the underlying Device object
|
||||
pub fn get_ref(&self) -> &Device {
|
||||
self.inner.get_ref()
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the underlying Device object
|
||||
pub fn get_mut(&mut self) -> &mut Device {
|
||||
self.inner.get_mut()
|
||||
}
|
||||
|
||||
/// Consumes this AsyncDevice and return a Framed object (unified Stream and Sink interface)
|
||||
pub fn into_framed(mut self) -> Framed<Self, TunPacketCodec> {
|
||||
let pi = self.get_mut().has_packet_information();
|
||||
let codec = TunPacketCodec::new(pi, self.inner.get_ref().mtu().unwrap_or(1504));
|
||||
Framed::new(self, codec)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncRead for AsyncDevice {
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut ReadBuf,
|
||||
) -> Poll<io::Result<()>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_read_ready_mut(cx))?;
|
||||
let rbuf = buf.initialize_unfilled();
|
||||
match guard.try_io(|inner| inner.get_mut().read(rbuf)) {
|
||||
Ok(res) => return Poll::Ready(res.map(|n| buf.advance(n))),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWrite for AsyncDevice {
|
||||
fn poll_write(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
|
||||
match guard.try_io(|inner| inner.get_mut().write(buf)) {
|
||||
Ok(res) => return Poll::Ready(res),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
|
||||
match guard.try_io(|inner| inner.get_mut().flush()) {
|
||||
Ok(res) => return Poll::Ready(res),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn poll_write_vectored(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
bufs: &[IoSlice<'_>],
|
||||
) -> Poll<Result<usize, io::Error>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
|
||||
match guard.try_io(|inner| inner.get_mut().write_vectored(bufs)) {
|
||||
Ok(res) => return Poll::Ready(res),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_write_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// An async TUN device queue wrapper around a TUN device queue.
|
||||
pub struct AsyncQueue {
|
||||
inner: AsyncFd<Queue>,
|
||||
}
|
||||
|
||||
impl AsyncQueue {
|
||||
/// Create a new `AsyncQueue` wrapping around a `Queue`.
|
||||
pub fn new(queue: Queue) -> io::Result<AsyncQueue> {
|
||||
queue.set_nonblock()?;
|
||||
Ok(AsyncQueue {
|
||||
inner: AsyncFd::new(queue)?,
|
||||
})
|
||||
}
|
||||
/// Returns a shared reference to the underlying Queue object
|
||||
pub fn get_ref(&self) -> &Queue {
|
||||
self.inner.get_ref()
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the underlying Queue object
|
||||
pub fn get_mut(&mut self) -> &mut Queue {
|
||||
self.inner.get_mut()
|
||||
}
|
||||
|
||||
/// Consumes this AsyncQueue and return a Framed object (unified Stream and Sink interface)
|
||||
pub fn into_framed(mut self) -> Framed<Self, TunPacketCodec> {
|
||||
let pi = self.get_mut().has_packet_information();
|
||||
let codec = TunPacketCodec::new(pi, 1504);
|
||||
Framed::new(self, codec)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncRead for AsyncQueue {
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut ReadBuf,
|
||||
) -> Poll<io::Result<()>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_read_ready_mut(cx))?;
|
||||
let rbuf = buf.initialize_unfilled();
|
||||
match guard.try_io(|inner| inner.get_mut().read(rbuf)) {
|
||||
Ok(res) => return Poll::Ready(res.map(|n| buf.advance(n))),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWrite for AsyncQueue {
|
||||
fn poll_write(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
|
||||
match guard.try_io(|inner| inner.get_mut().write(buf)) {
|
||||
Ok(res) => return Poll::Ready(res),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
|
||||
match guard.try_io(|inner| inner.get_mut().flush()) {
|
||||
Ok(res) => return Poll::Ready(res),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// 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.
|
||||
|
||||
//! Async specific modules.
|
||||
|
||||
use crate::error;
|
||||
|
||||
use crate::configuration::Configuration;
|
||||
use crate::platform::create;
|
||||
|
||||
mod device;
|
||||
pub use self::device::{AsyncDevice, AsyncQueue};
|
||||
|
||||
mod codec;
|
||||
pub use self::codec::{TunPacket, TunPacketCodec};
|
||||
|
||||
/// Create a TUN device with the given name.
|
||||
pub fn create_as_async(configuration: &Configuration) -> Result<AsyncDevice, error::Error> {
|
||||
let device = create(&configuration)?;
|
||||
AsyncDevice::new(device).map_err(|err| err.into())
|
||||
}
|
||||
@@ -12,15 +12,14 @@
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
use std::io::{Read, Write};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::configuration::Configuration;
|
||||
use crate::error::*;
|
||||
|
||||
/// A TUN device.
|
||||
pub trait Device: Read + Write {
|
||||
type Queue: Read + Write;
|
||||
pub trait Device {
|
||||
type Queue ;
|
||||
|
||||
/// Reconfigure the device.
|
||||
fn configure(&mut self, config: &Configuration) -> Result<()> {
|
||||
@@ -91,5 +90,5 @@ pub trait Device: Read + Write {
|
||||
fn set_mtu(&mut self, value: i32) -> Result<()>;
|
||||
|
||||
/// Get a device queue.
|
||||
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue>;
|
||||
fn queue(&self, index: usize) -> Option<&Self::Queue>;
|
||||
}
|
||||
|
||||
@@ -27,27 +27,6 @@ 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",
|
||||
target_os = "ios",
|
||||
target_os = "android"
|
||||
)
|
||||
))]
|
||||
pub mod r#async;
|
||||
#[cfg(all(
|
||||
feature = "async",
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "android"
|
||||
)
|
||||
))]
|
||||
pub use r#async::*;
|
||||
|
||||
pub fn configure() -> Configuration {
|
||||
Configuration::default()
|
||||
}
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// 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)
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// 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)
|
||||
}
|
||||
@@ -13,10 +13,10 @@
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::vec::Vec;
|
||||
@@ -77,10 +77,10 @@ impl Device {
|
||||
|
||||
req.ifru.flags = device_type
|
||||
| if config.platform.packet_information {
|
||||
0
|
||||
} else {
|
||||
IFF_NO_PI
|
||||
}
|
||||
0
|
||||
} else {
|
||||
IFF_NO_PI
|
||||
}
|
||||
| if queues_num > 1 { IFF_MULTI_QUEUE } else { 0 };
|
||||
|
||||
for _ in 0..queues_num {
|
||||
@@ -92,7 +92,7 @@ impl Device {
|
||||
}
|
||||
|
||||
queues.push(Queue {
|
||||
tun,
|
||||
tun: Arc::new(tun),
|
||||
pi_enabled: config.platform.packet_information,
|
||||
});
|
||||
}
|
||||
@@ -126,45 +126,40 @@ impl Device {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
// /// 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()))
|
||||
}
|
||||
// /// 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(())
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
/// Return whether the device has packet information
|
||||
pub fn has_packet_information(&mut self) -> bool {
|
||||
pub fn has_packet_information(&self) -> bool {
|
||||
self.queues[0].has_packet_information()
|
||||
}
|
||||
|
||||
@@ -174,30 +169,6 @@ impl Device {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -377,73 +348,29 @@ impl D for Device {
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
fn queue(&self, index: usize) -> Option<&Self::Queue> {
|
||||
self.queues.get(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Queue {
|
||||
tun: Fd,
|
||||
tun: Arc<Fd>,
|
||||
pi_enabled: bool,
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
pub fn has_packet_information(&mut self) -> bool {
|
||||
pub fn has_packet_information(&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)
|
||||
pub fn reader(&self) -> posix::Reader {
|
||||
posix::Reader(self.tun.clone())
|
||||
}
|
||||
|
||||
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()
|
||||
pub fn writer(&self) -> posix::Writer {
|
||||
posix::Writer(self.tun.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
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 libc::{AF_INET, c_char, c_uint, c_void, SOCK_DGRAM, sockaddr, socklen_t};
|
||||
|
||||
use crate::configuration::{Configuration, Layer};
|
||||
use crate::device::Device as D;
|
||||
@@ -121,7 +121,7 @@ impl Device {
|
||||
name: CStr::from_ptr(name.as_ptr() as *const c_char)
|
||||
.to_string_lossy()
|
||||
.into(),
|
||||
queue: Queue { tun: tun },
|
||||
queue: Queue { tun: Arc::new(tun) },
|
||||
ctl: ctl,
|
||||
}
|
||||
};
|
||||
@@ -165,11 +165,11 @@ impl 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()))
|
||||
}
|
||||
// /// 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 {
|
||||
@@ -182,29 +182,29 @@ impl Device {
|
||||
}
|
||||
}
|
||||
|
||||
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 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;
|
||||
@@ -365,29 +365,29 @@ impl D for Device {
|
||||
}
|
||||
}
|
||||
|
||||
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
|
||||
fn queue(&self, index: usize) -> Option<&Self::Queue> {
|
||||
if index > 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(&mut self.queue)
|
||||
Some(&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()
|
||||
}
|
||||
}
|
||||
// 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,
|
||||
tun: Arc<Fd>,
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
@@ -399,40 +399,47 @@ impl Queue {
|
||||
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()
|
||||
pub fn reader(&self) -> posix::Reader {
|
||||
posix::Reader(self.tun.clone())
|
||||
}
|
||||
pub fn writer(&self) -> posix::Writer {
|
||||
posix::Writer(self.tun.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Queue {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.tun.into_raw_fd()
|
||||
}
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
// 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)
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -12,22 +12,24 @@
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
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.
|
||||
#[derive(Clone)]
|
||||
pub struct Reader(pub(crate) Arc<Fd>);
|
||||
|
||||
/// Write-only end for a file descriptor.
|
||||
#[derive(Clone)]
|
||||
pub struct Writer(pub(crate) Arc<Fd>);
|
||||
|
||||
impl Read for Reader {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
impl Reader {
|
||||
pub fn read(&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());
|
||||
|
||||
@@ -39,7 +41,7 @@ impl Read for Reader {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
pub fn read_vectored(&self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let mut msg: libc::msghdr = mem::zeroed();
|
||||
// msg.msg_name: NULL
|
||||
@@ -57,8 +59,8 @@ impl Read for Reader {
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Writer {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
impl Writer {
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let amount = libc::write(self.0.as_raw_fd(), buf.as_ptr() as *const _, buf.len());
|
||||
|
||||
@@ -70,11 +72,8 @@ impl Write for Writer {
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
pub fn write_vectored(&self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let mut msg: libc::msghdr = mem::zeroed();
|
||||
// msg.msg_name = NULL
|
||||
@@ -90,6 +89,22 @@ impl Write for Writer {
|
||||
Ok(n as usize)
|
||||
}
|
||||
}
|
||||
pub fn write_all(&self, mut buf: &[u8]) -> io::Result<()> {
|
||||
while !buf.is_empty() {
|
||||
match self.write(buf) {
|
||||
Ok(0) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::WriteZero,
|
||||
"failed to write whole buffer",
|
||||
));
|
||||
}
|
||||
Ok(n) => buf = &buf[n..],
|
||||
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Reader {
|
||||
@@ -97,9 +112,9 @@ impl AsRawFd for Reader {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Writer {
|
||||
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()
|
||||
// }
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user