// Copyright 2017 The ChromiumOS Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Network API wrappers for TAP interfaces. //! # Slirp specific crate features //! * **guest-to-host-net-loopback** - Enables the guest to reach the host at a well known IP //! address on the virtual network. //! * **slirp** - Enables the libslirp backend for virtio-net. //! * **slirp-debug** - Enables capture of all packets sent through libslirp in a pcap file. //! * **slirp-ring-capture** - Captures packets in a ring buffer and dumps them to a pcap file on //! exit. 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 { /// Unable to clone tap interface. #[error("failed to clone tap interface: {0}")] CloneTap(SysError), /// Failed to create a socket. #[error("failed to create a socket: {0}")] CreateSocket(SysError), /// Unable to create tap interface. #[error("failed to create tap interface: {0}")] CreateTap(SysError), /// ioctl failed. #[error("ioctl failed: {0}")] IoctlError(SysError), /// Couldn't open /dev/net/tun. #[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 = std::result::Result; 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 { /// Invalid number of octets. #[error("invalid number of octets: {0}")] InvalidNumOctets(usize), /// Failed to parse octet. #[error("failed to parse octet: {0}")] ParseOctet(ParseIntError), } /// An Ethernet MAC address. #[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 { 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(deserializer: D) -> std::result::Result 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(&self, serializer: S) -> std::result::Result where S: Serializer, { serializer.collect_str(&self) } } pub trait TapTCommon: Read + Write + AsRawDescriptor + Send + Sized { /// Create a new tap interface named `name`, or open it if it already exists with the same /// parameters. /// /// Set the `vnet_hdr` flag to true to allow offloading on this tap, which will add an extra 12 /// byte virtio net header to incoming frames. Offloading cannot be used if `vnet_hdr` is false. /// Set 'multi_vq' to true, if tap have multi virt queue pairs fn new_with_name(name: &[u8], vnet_hdr: bool, multi_vq: bool) -> Result; /// Create a new tap interface. Set the `vnet_hdr` flag to true to allow offloading on this tap, /// which will add an extra 12 byte virtio net header to incoming frames. Offloading cannot /// be used if `vnet_hdr` is false. Set 'multi_vq' to true if tap has multi virt queue pairs. fn new(vnet_hdr: bool, multi_vq: bool) -> Result; /// Change the origin tap into multiqueue taps, this means create other taps based on the /// origin tap. fn into_mq_taps(self, vq_pairs: u16) -> Result>; /// Get the host-side IP address for the tap interface. fn ip_addr(&self) -> Result; /// Set the host-side IP address for the tap interface. fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()>; /// Get the netmask for the tap interface's subnet. fn netmask(&self) -> Result; /// Set the netmask for the subnet that the tap interface will exist on. fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()>; /// Get the MTU for the tap interface. fn mtu(&self) -> Result; /// Set the MTU for the tap interface. fn set_mtu(&self, mtu: u16) -> Result<()>; /// Get the mac address for the tap interface. fn mac_address(&self) -> Result; /// Set the mac address for the tap interface. fn set_mac_address(&self, mac_addr: MacAddress) -> Result<()>; /// Set the offload flags for the tap interface. fn set_offload(&self, flags: c_uint) -> Result<()>; /// Enable the tap interface. fn enable(&self) -> Result<()>; /// Try to clone fn try_clone(&self) -> Result; /// Convert raw descriptor to /// /// # Safety /// /// Caller must ensure that RawDescriptor stays valid as long as the lifetime /// of Self. unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Result; } #[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::(SERIALIZED_ADDRESS).unwrap(), mac_address ); } }