Skip to content

Commit

Permalink
support ios
Browse files Browse the repository at this point in the history
  • Loading branch information
eycorsican committed Aug 8, 2020
1 parent e82fbb9 commit b5cdf61
Show file tree
Hide file tree
Showing 10 changed files with 648 additions and 332 deletions.
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ keywords = ["tun", "network", "tunnel", "bindings"]
libc = "0.2"
thiserror = "1"

[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
ioctl = { version = "0.5", package = "ioctl-sys" }
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "ios"))'.dependencies]
mio = { version = "0.6", optional = true }
tokio = { version = "0.2", features = ["full"], optional = true }
tokio-util = { version = "0.3", features = ["codec"], optional = true }
bytes = { version = "0.5", optional = true }
byteorder = { version = "1.3", optional = true }

[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
ioctl = { version = "0.5", package = "ioctl-sys" }

[dev-dependencies]
packet = "0.1"
futures = "0.3.1"
Expand Down
190 changes: 95 additions & 95 deletions src/async/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,36 +21,36 @@ use tokio_util::codec::{Decoder, Encoder};
/// A packet protocol IP version
#[derive(Debug)]
enum PacketProtocol {
IPv4,
IPv6,
Other(u8),
IPv4,
IPv6,
Other(u8),
}

// Note: the protocol in the packet information header is platform dependent.
impl PacketProtocol {
#[cfg(target_os = "linux")]
fn into_pi_field(&self) -> Result<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(target_os = "macos")]
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",
)),
}
}
#[cfg(target_os = "linux")]
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.
Expand All @@ -59,88 +59,88 @@ pub struct TunPacket(PacketProtocol, Bytes);

/// Infer the protocol based on the first nibble in the packet buffer.
fn infer_proto(buf: &[u8]) -> PacketProtocol {
match buf[0] >> 4 {
4 => PacketProtocol::IPv4,
6 => PacketProtocol::IPv6,
p => PacketProtocol::Other(p),
}
match buf[0] >> 4 {
4 => PacketProtocol::IPv4,
6 => PacketProtocol::IPv6,
p => PacketProtocol::Other(p),
}
}

impl TunPacket {
/// Create a new `TunPacket` based on a byte slice.
pub fn new(bytes: Vec<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
}
/// 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
}
}

/// A TunPacket Encoder/Decoder.
pub struct TunPacketCodec(bool);

impl TunPacketCodec {
/// Create a new `TunPacketCodec` specifying whether the underlying
/// tunnel Device has enabled the packet information header.
pub fn new(pi: bool) -> TunPacketCodec {
TunPacketCodec(pi)
}
/// Create a new `TunPacketCodec` specifying whether the underlying
/// tunnel Device has enabled the packet information header.
pub fn new(pi: bool) -> TunPacketCodec {
TunPacketCodec(pi)
}
}

impl Decoder for TunPacketCodec {
type Item = TunPacket;
type Error = io::Error;

fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
if buf.is_empty() {
return Ok(None);
}

if self.0 {
// ignore malformed packet
if buf.len() <= 4 {
let _ = buf.split_to(buf.len());
return Ok(None);
}
}

let mut buf = buf.split_to(buf.len());

// if the packet information is enabled we have to ignore the first 4 bytes
if self.0 {
let _ = buf.split_to(4);
}

let proto = infer_proto(buf.as_ref());
Ok(Some(TunPacket(proto, buf.freeze())))
}
type Item = TunPacket;
type Error = io::Error;

fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
if buf.is_empty() {
return Ok(None);
}

if self.0 {
// ignore malformed packet
if buf.len() <= 4 {
let _ = buf.split_to(buf.len());
return Ok(None);
}
}

let mut buf = buf.split_to(buf.len());

// if the packet information is enabled we have to ignore the first 4 bytes
if self.0 {
let _ = buf.split_to(4);
}

let proto = infer_proto(buf.as_ref());
Ok(Some(TunPacket(proto, buf.freeze())))
}
}

impl Encoder<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(())
}
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(())
}
}

0 comments on commit b5cdf61

Please sign in to comment.