pub mod sys;
use std::fmt;
use std::fmt::Display;
use std::io::Read;
use std::io::Write;
use std::net;
use std::num::ParseIntError;
use std::os::raw::*;
use std::str::FromStr;
use base::AsRawDescriptor;
use base::Error as SysError;
use base::RawDescriptor;
use remain::sorted;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;
use serde::Serializer;
pub use sys::TapT;
use thiserror::Error as ThisError;
#[cfg(feature = "slirp")]
pub mod slirp;
#[cfg(all(feature = "slirp", windows))]
pub use slirp::Slirp;
#[sorted]
#[derive(ThisError, Debug)]
pub enum Error {
#[error("failed to clone tap interface: {0}")]
CloneTap(SysError),
#[error("failed to create a socket: {0}")]
CreateSocket(SysError),
#[error("failed to create tap interface: {0}")]
CreateTap(SysError),
#[error("ioctl failed: {0}")]
IoctlError(SysError),
#[error("failed to open /dev/net/tun: {0}")]
OpenTun(SysError),
#[cfg(all(feature = "slirp", windows))]
#[error("slirp related error")]
Slirp(slirp::SlirpError),
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
pub fn sys_error(&self) -> SysError {
match self {
Error::CreateSocket(e) => *e,
Error::OpenTun(e) => *e,
Error::CreateTap(e) => *e,
Error::CloneTap(e) => *e,
Error::IoctlError(e) => *e,
#[cfg(all(feature = "slirp", windows))]
Error::Slirp(e) => e.sys_error(),
}
}
}
#[sorted]
#[derive(ThisError, Debug, PartialEq, Eq)]
pub enum MacAddressError {
#[error("invalid number of octets: {0}")]
InvalidNumOctets(usize),
#[error("failed to parse octet: {0}")]
ParseOctet(ParseIntError),
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub struct MacAddress {
addr: [u8; 6],
}
impl MacAddress {
pub fn octets(&self) -> [u8; 6] {
self.addr
}
}
impl FromStr for MacAddress {
type Err = MacAddressError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
let octets: Vec<&str> = s.split(':').collect();
if octets.len() != 6usize {
return Err(MacAddressError::InvalidNumOctets(octets.len()));
}
let mut result = MacAddress::default();
for (i, octet) in octets.iter().enumerate() {
result.addr[i] = u8::from_str_radix(octet, 16).map_err(MacAddressError::ParseOctet)?;
}
Ok(result)
}
}
impl Display for MacAddress {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
self.addr[0], self.addr[1], self.addr[2], self.addr[3], self.addr[4], self.addr[5]
)
}
}
impl<'de> Deserialize<'de> for MacAddress {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
FromStr::from_str(&s).map_err(serde::de::Error::custom)
}
}
impl Serialize for MacAddress {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_str(&self)
}
}
pub trait TapTCommon: Read + Write + AsRawDescriptor + Send + Sized {
fn new_with_name(name: &[u8], vnet_hdr: bool, multi_vq: bool) -> Result<Self>;
fn new(vnet_hdr: bool, multi_vq: bool) -> Result<Self>;
fn into_mq_taps(self, vq_pairs: u16) -> Result<Vec<Self>>;
fn ip_addr(&self) -> Result<net::Ipv4Addr>;
fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()>;
fn netmask(&self) -> Result<net::Ipv4Addr>;
fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()>;
fn mtu(&self) -> Result<u16>;
fn set_mtu(&self, mtu: u16) -> Result<()>;
fn mac_address(&self) -> Result<MacAddress>;
fn set_mac_address(&self, mac_addr: MacAddress) -> Result<()>;
fn set_offload(&self, flags: c_uint) -> Result<()>;
fn enable(&self) -> Result<()>;
fn try_clone(&self) -> Result<Self>;
unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Result<Self>;
}
#[cfg(test)]
mod tests {
use serde_json::*;
use super::*;
#[test]
fn json_serialize_deserialize() {
let mac_address = MacAddress {
addr: [0x3d, 0x70, 0xeb, 0x61, 0x1a, 0x91],
};
const SERIALIZED_ADDRESS: &str = "\"3D:70:EB:61:1A:91\"";
assert_eq!(to_string(&mac_address).unwrap(), SERIALIZED_ADDRESS);
assert_eq!(
from_str::<MacAddress>(SERIALIZED_ADDRESS).unwrap(),
mac_address
);
}
}