#[cfg(test)]
mod net_test;
use std::collections::HashMap;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::str::FromStr;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use async_trait::async_trait;
use ipnet::IpNet;
use portable_atomic::AtomicU64;
use tokio::net::UdpSocket;
use tokio::sync::Mutex;
use super::conn_map::*;
use super::interface::*;
use crate::error::*;
use crate::vnet::chunk::Chunk;
use crate::vnet::conn::{ConnObserver, UdpConn};
use crate::vnet::router::*;
use crate::{conn, ifaces, Conn};
pub(crate) const LO0_STR: &str = "lo0";
pub(crate) const UDP_STR: &str = "udp";
lazy_static! {
pub static ref MAC_ADDR_COUNTER: AtomicU64 = AtomicU64::new(0xBEEFED910200);
}
pub(crate) type HardwareAddr = Vec<u8>;
pub(crate) fn new_mac_address() -> HardwareAddr {
let b = MAC_ADDR_COUNTER
.fetch_add(1, Ordering::SeqCst)
.to_be_bytes();
b[2..].to_vec()
}
#[derive(Default)]
pub(crate) struct VNetInternal {
pub(crate) interfaces: Vec<Interface>, pub(crate) router: Option<Arc<Mutex<Router>>>, pub(crate) udp_conns: UdpConnMap, }
impl VNetInternal {
fn get_interface(&self, ifc_name: &str) -> Option<&Interface> {
self.interfaces.iter().find(|ifc| ifc.name == ifc_name)
}
}
#[async_trait]
impl ConnObserver for VNetInternal {
async fn write(&self, c: Box<dyn Chunk + Send + Sync>) -> Result<()> {
if c.network() == UDP_STR && c.get_destination_ip().is_loopback() {
if let Some(conn) = self.udp_conns.find(&c.destination_addr()).await {
let read_ch_tx = conn.get_inbound_ch();
let ch_tx = read_ch_tx.lock().await;
if let Some(tx) = &*ch_tx {
let _ = tx.send(c).await;
}
}
return Ok(());
}
if let Some(r) = &self.router {
let p = r.lock().await;
p.push(c).await;
Ok(())
} else {
Err(Error::ErrNoRouterLinked)
}
}
async fn on_closed(&self, addr: SocketAddr) {
let _ = self.udp_conns.delete(&addr).await;
}
fn determine_source_ip(&self, loc_ip: IpAddr, dst_ip: IpAddr) -> Option<IpAddr> {
if !loc_ip.is_unspecified() {
return Some(loc_ip);
}
if dst_ip.is_loopback() {
let src_ip = if let Ok(src_ip) = IpAddr::from_str("127.0.0.1") {
Some(src_ip)
} else {
None
};
return src_ip;
}
if let Some(ifc) = self.get_interface("eth0") {
for ipnet in ifc.addrs() {
if (ipnet.addr().is_ipv4() && loc_ip.is_ipv4())
|| (ipnet.addr().is_ipv6() && loc_ip.is_ipv6())
{
return Some(ipnet.addr());
}
}
}
None
}
}
#[derive(Default)]
pub struct VNet {
pub(crate) interfaces: Vec<Interface>, pub(crate) static_ips: Vec<IpAddr>, pub(crate) vi: Arc<Mutex<VNetInternal>>,
}
#[async_trait]
impl Nic for VNet {
async fn get_interface(&self, ifc_name: &str) -> Option<Interface> {
for ifc in &self.interfaces {
if ifc.name == ifc_name {
return Some(ifc.clone());
}
}
None
}
async fn add_addrs_to_interface(&mut self, ifc_name: &str, addrs: &[IpNet]) -> Result<()> {
{
let mut vi = self.vi.lock().await;
for ifc in &mut vi.interfaces {
if ifc.name == ifc_name {
for addr in addrs {
ifc.add_addr(*addr);
}
break;
}
}
}
for ifc in &mut self.interfaces {
if ifc.name == ifc_name {
for addr in addrs {
ifc.add_addr(*addr);
}
return Ok(());
}
}
Err(Error::ErrNotFound)
}
async fn set_router(&self, r: Arc<Mutex<Router>>) -> Result<()> {
let mut vi = self.vi.lock().await;
vi.router = Some(r);
Ok(())
}
async fn on_inbound_chunk(&self, c: Box<dyn Chunk + Send + Sync>) {
if c.network() == UDP_STR {
let vi = self.vi.lock().await;
if let Some(conn) = vi.udp_conns.find(&c.destination_addr()).await {
let read_ch_tx = conn.get_inbound_ch();
let ch_tx = read_ch_tx.lock().await;
if let Some(tx) = &*ch_tx {
let _ = tx.send(c).await;
}
}
}
}
async fn get_static_ips(&self) -> Vec<IpAddr> {
self.static_ips.clone()
}
}
impl VNet {
pub(crate) fn get_interfaces(&self) -> &[Interface] {
&self.interfaces
}
pub(crate) fn get_all_ipaddrs(&self, ipv6: bool) -> Vec<IpAddr> {
let mut ips = vec![];
for ifc in &self.interfaces {
for ipnet in ifc.addrs() {
if (ipv6 && ipnet.addr().is_ipv6()) || (!ipv6 && ipnet.addr().is_ipv4()) {
ips.push(ipnet.addr());
}
}
}
ips
}
pub(crate) fn has_ipaddr(&self, ip: IpAddr) -> bool {
for ifc in &self.interfaces {
for ipnet in ifc.addrs() {
let loc_ip = ipnet.addr();
match ip.to_string().as_str() {
"0.0.0.0" => {
if loc_ip.is_ipv4() {
return true;
}
}
"::" => {
if loc_ip.is_ipv6() {
return true;
}
}
_ => {
if loc_ip == ip {
return true;
}
}
}
}
}
false
}
pub(crate) async fn allocate_local_addr(&self, ip: IpAddr, port: u16) -> Result<()> {
let mut ips = vec![];
if ip.is_unspecified() {
ips = self.get_all_ipaddrs(ip.is_ipv6());
} else if self.has_ipaddr(ip) {
ips.push(ip);
}
if ips.is_empty() {
return Err(Error::ErrBindFailed);
}
for ip2 in ips {
let addr = SocketAddr::new(ip2, port);
let vi = self.vi.lock().await;
if vi.udp_conns.find(&addr).await.is_some() {
return Err(Error::ErrAddressAlreadyInUse);
}
}
Ok(())
}
pub(crate) async fn assign_port(&self, ip: IpAddr, start: u16, end: u16) -> Result<u16> {
if end < start {
return Err(Error::ErrEndPortLessThanStart);
}
let space = end + 1 - start;
let offset = rand::random::<u16>() % space;
for i in 0..space {
let port = ((offset + i) % space) + start;
let result = self.allocate_local_addr(ip, port).await;
if result.is_ok() {
return Ok(port);
}
}
Err(Error::ErrPortSpaceExhausted)
}
pub(crate) async fn resolve_addr(&self, use_ipv4: bool, address: &str) -> Result<SocketAddr> {
let v: Vec<&str> = address.splitn(2, ':').collect();
if v.len() != 2 {
return Err(Error::ErrAddrNotUdpAddr);
}
let (host, port) = (v[0], v[1]);
let ip: IpAddr = match host.parse() {
Ok(ip) => ip,
Err(_) => {
let host = host.to_lowercase();
if host == "localhost" {
if use_ipv4 {
Ipv4Addr::new(127, 0, 0, 1).into()
} else {
Ipv6Addr::from_str("::1")?.into()
}
} else {
let vi = self.vi.lock().await;
if let Some(router) = &vi.router {
let r = router.lock().await;
let resolver = r.resolver.lock().await;
if let Some(ip) = resolver.lookup(host).await {
ip
} else {
return Err(Error::ErrNotFound);
}
} else {
return Err(Error::ErrNoRouterLinked);
}
}
}
};
let port: u16 = port.parse()?;
let remote_addr = SocketAddr::new(ip, port);
if (use_ipv4 && remote_addr.is_ipv4()) || (!use_ipv4 && remote_addr.is_ipv6()) {
Ok(remote_addr)
} else {
Err(Error::Other(format!(
"No available {} IP address found!",
if use_ipv4 { "ipv4" } else { "ipv6" },
)))
}
}
pub(crate) async fn bind(
&self,
mut local_addr: SocketAddr,
) -> Result<Arc<dyn Conn + Send + Sync>> {
if !self.has_ipaddr(local_addr.ip()) {
return Err(Error::ErrCantAssignRequestedAddr);
}
if local_addr.port() == 0 {
local_addr.set_port(self.assign_port(local_addr.ip(), 5000, 5999).await?);
} else {
let vi = self.vi.lock().await;
if vi.udp_conns.find(&local_addr).await.is_some() {
return Err(Error::ErrAddressAlreadyInUse);
}
}
let v = Arc::clone(&self.vi) as Arc<Mutex<dyn ConnObserver + Send + Sync>>;
let conn = Arc::new(UdpConn::new(local_addr, None, v));
{
let vi = self.vi.lock().await;
vi.udp_conns.insert(Arc::clone(&conn)).await?;
}
Ok(conn)
}
pub(crate) async fn dail(
&self,
use_ipv4: bool,
remote_addr: &str,
) -> Result<Arc<dyn Conn + Send + Sync>> {
let rem_addr = self.resolve_addr(use_ipv4, remote_addr).await?;
let src_ip = {
let vi = self.vi.lock().await;
let any_ip = if use_ipv4 {
Ipv4Addr::new(0, 0, 0, 0).into()
} else {
Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).into()
};
if let Some(src_ip) = vi.determine_source_ip(any_ip, rem_addr.ip()) {
src_ip
} else {
any_ip
}
};
let loc_addr = SocketAddr::new(src_ip, 0);
let conn = self.bind(loc_addr).await?;
conn.connect(rem_addr).await?;
Ok(conn)
}
}
#[derive(Debug, Default)]
pub struct NetConfig {
pub static_ips: Vec<String>,
pub static_ip: String,
}
pub enum Net {
VNet(Arc<Mutex<VNet>>),
Ifs(Vec<Interface>),
}
impl Net {
pub fn new(config: Option<NetConfig>) -> Self {
if let Some(config) = config {
let mut lo0 = Interface::new(LO0_STR.to_owned(), vec![]);
if let Ok(ipnet) = Interface::convert(
SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 0),
Some(SocketAddr::new(Ipv4Addr::new(255, 0, 0, 0).into(), 0)),
) {
lo0.add_addr(ipnet);
}
let eth0 = Interface::new("eth0".to_owned(), vec![]);
let mut static_ips = vec![];
for ip_str in &config.static_ips {
if let Ok(ip) = IpAddr::from_str(ip_str) {
static_ips.push(ip);
}
}
if !config.static_ip.is_empty() {
if let Ok(ip) = IpAddr::from_str(&config.static_ip) {
static_ips.push(ip);
}
}
let vnet = VNet {
interfaces: vec![lo0.clone(), eth0.clone()],
static_ips,
vi: Arc::new(Mutex::new(VNetInternal {
interfaces: vec![lo0, eth0],
router: None,
udp_conns: UdpConnMap::new(),
})),
};
Net::VNet(Arc::new(Mutex::new(vnet)))
} else {
let interfaces = match ifaces::ifaces() {
Ok(ifs) => ifs,
Err(_) => vec![],
};
let mut m: HashMap<String, Vec<IpNet>> = HashMap::new();
for iface in interfaces {
if let Some(addrs) = m.get_mut(&iface.name) {
if let Some(addr) = iface.addr {
if let Ok(inet) = Interface::convert(addr, iface.mask) {
addrs.push(inet);
}
}
} else if let Some(addr) = iface.addr {
if let Ok(inet) = Interface::convert(addr, iface.mask) {
m.insert(iface.name, vec![inet]);
}
}
}
let mut ifs = vec![];
for (name, addrs) in m.into_iter() {
ifs.push(Interface::new(name, addrs));
}
Net::Ifs(ifs)
}
}
pub async fn get_interfaces(&self) -> Vec<Interface> {
match self {
Net::VNet(vnet) => {
let net = vnet.lock().await;
net.get_interfaces().to_vec()
}
Net::Ifs(ifs) => ifs.clone(),
}
}
pub async fn get_interface(&self, ifc_name: &str) -> Option<Interface> {
match self {
Net::VNet(vnet) => {
let net = vnet.lock().await;
net.get_interface(ifc_name).await
}
Net::Ifs(ifs) => {
for ifc in ifs {
if ifc.name == ifc_name {
return Some(ifc.clone());
}
}
None
}
}
}
pub fn is_virtual(&self) -> bool {
match self {
Net::VNet(_) => true,
Net::Ifs(_) => false,
}
}
pub async fn resolve_addr(&self, use_ipv4: bool, address: &str) -> Result<SocketAddr> {
match self {
Net::VNet(vnet) => {
let net = vnet.lock().await;
net.resolve_addr(use_ipv4, address).await
}
Net::Ifs(_) => Ok(conn::lookup_host(use_ipv4, address).await?),
}
}
pub async fn bind(&self, addr: SocketAddr) -> Result<Arc<dyn Conn + Send + Sync>> {
match self {
Net::VNet(vnet) => {
let net = vnet.lock().await;
net.bind(addr).await
}
Net::Ifs(_) => Ok(Arc::new(UdpSocket::bind(addr).await?)),
}
}
pub async fn dail(
&self,
use_ipv4: bool,
remote_addr: &str,
) -> Result<Arc<dyn Conn + Send + Sync>> {
match self {
Net::VNet(vnet) => {
let net = vnet.lock().await;
net.dail(use_ipv4, remote_addr).await
}
Net::Ifs(_) => {
let any_ip = if use_ipv4 {
Ipv4Addr::new(0, 0, 0, 0).into()
} else {
Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).into()
};
let local_addr = SocketAddr::new(any_ip, 0);
let conn = UdpSocket::bind(local_addr).await?;
conn.connect(remote_addr).await?;
Ok(Arc::new(conn))
}
}
}
pub fn get_nic(&self) -> Result<Arc<Mutex<dyn Nic + Send + Sync>>> {
match self {
Net::VNet(vnet) => Ok(Arc::clone(vnet) as Arc<Mutex<dyn Nic + Send + Sync>>),
Net::Ifs(_) => Err(Error::ErrVnetDisabled),
}
}
}