mirror of
				https://github.com/edera-dev/krata.git
				synced 2025-11-03 23:29:39 +00:00 
			
		
		
		
	network: implement host bridging
This commit is contained in:
		
							
								
								
									
										146
									
								
								network/src/hbridge.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								network/src/hbridge.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,146 @@
 | 
			
		||||
use std::net::{IpAddr, Ipv4Addr};
 | 
			
		||||
 | 
			
		||||
use advmac::MacAddr6;
 | 
			
		||||
use anyhow::{anyhow, Result};
 | 
			
		||||
use bytes::BytesMut;
 | 
			
		||||
use futures::TryStreamExt;
 | 
			
		||||
use log::error;
 | 
			
		||||
use smoltcp::wire::EthernetAddress;
 | 
			
		||||
use tokio::{
 | 
			
		||||
    io::{AsyncReadExt, AsyncWriteExt},
 | 
			
		||||
    select,
 | 
			
		||||
    sync::mpsc::channel,
 | 
			
		||||
    task::JoinHandle,
 | 
			
		||||
};
 | 
			
		||||
use tokio_tun::Tun;
 | 
			
		||||
 | 
			
		||||
use crate::vbridge::{BridgeJoinHandle, VirtualBridge};
 | 
			
		||||
 | 
			
		||||
pub struct HostBridge {
 | 
			
		||||
    task: JoinHandle<()>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl HostBridge {
 | 
			
		||||
    pub async fn new(interface: String, bridge: &VirtualBridge) -> Result<HostBridge> {
 | 
			
		||||
        let tun = Tun::builder()
 | 
			
		||||
            .name(&interface)
 | 
			
		||||
            .tap(true)
 | 
			
		||||
            .mtu(1500)
 | 
			
		||||
            .packet_info(false)
 | 
			
		||||
            .try_build()?;
 | 
			
		||||
 | 
			
		||||
        let (connection, handle, _) = rtnetlink::new_connection()?;
 | 
			
		||||
        tokio::spawn(connection);
 | 
			
		||||
 | 
			
		||||
        let mut mac = MacAddr6::random();
 | 
			
		||||
        mac.set_local(true);
 | 
			
		||||
        mac.set_multicast(false);
 | 
			
		||||
 | 
			
		||||
        let mut links = handle.link().get().match_name(interface.clone()).execute();
 | 
			
		||||
        let link = links.try_next().await?;
 | 
			
		||||
        if link.is_none() {
 | 
			
		||||
            return Err(anyhow!(
 | 
			
		||||
                "unable to find network interface named {}",
 | 
			
		||||
                interface
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
        let link = link.unwrap();
 | 
			
		||||
 | 
			
		||||
        handle
 | 
			
		||||
            .address()
 | 
			
		||||
            .add(
 | 
			
		||||
                link.header.index,
 | 
			
		||||
                IpAddr::V4(Ipv4Addr::new(10, 75, 0, 1)),
 | 
			
		||||
                16,
 | 
			
		||||
            )
 | 
			
		||||
            .execute()
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        handle
 | 
			
		||||
            .address()
 | 
			
		||||
            .add(link.header.index, IpAddr::V6(mac.to_link_local_ipv6()), 10)
 | 
			
		||||
            .execute()
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        handle
 | 
			
		||||
            .link()
 | 
			
		||||
            .set(link.header.index)
 | 
			
		||||
            .address(mac.to_array().to_vec())
 | 
			
		||||
            .up()
 | 
			
		||||
            .execute()
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        let mac = EthernetAddress(mac.to_array());
 | 
			
		||||
        let bridge_handle = bridge.join(mac).await?;
 | 
			
		||||
 | 
			
		||||
        let task = tokio::task::spawn(async move {
 | 
			
		||||
            if let Err(error) = HostBridge::process(tun, bridge_handle).await {
 | 
			
		||||
                error!("failed to process host bridge: {}", error);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Ok(HostBridge { task })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn process(tun: Tun, mut bridge_handle: BridgeJoinHandle) -> Result<()> {
 | 
			
		||||
        let (rx_sender, mut rx_receiver) = channel::<BytesMut>(100);
 | 
			
		||||
        let (mut read, mut write) = tokio::io::split(tun);
 | 
			
		||||
        tokio::task::spawn(async move {
 | 
			
		||||
            let mut buffer = vec![0u8; 1500];
 | 
			
		||||
            loop {
 | 
			
		||||
                let size = match read.read(&mut buffer).await {
 | 
			
		||||
                    Ok(size) => size,
 | 
			
		||||
                    Err(error) => {
 | 
			
		||||
                        error!("failed to read tap device: {}", error);
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                match rx_sender.send(buffer[0..size].into()).await {
 | 
			
		||||
                    Ok(_) => {}
 | 
			
		||||
                    Err(error) => {
 | 
			
		||||
                        error!(
 | 
			
		||||
                            "failed to send data from tap device to processor: {}",
 | 
			
		||||
                            error
 | 
			
		||||
                        );
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        loop {
 | 
			
		||||
            select! {
 | 
			
		||||
                x = bridge_handle.from_bridge_receiver.recv() => match x {
 | 
			
		||||
                    Some(bytes) => {
 | 
			
		||||
                        write.write_all(&bytes).await?;
 | 
			
		||||
                    },
 | 
			
		||||
                    None => {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                x = bridge_handle.from_broadcast_receiver.recv() => match x {
 | 
			
		||||
                    Ok(bytes) => {
 | 
			
		||||
                        write.write_all(&bytes).await?;
 | 
			
		||||
                    },
 | 
			
		||||
                    Err(error) => {
 | 
			
		||||
                        return Err(error.into());
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                x = rx_receiver.recv() => match x {
 | 
			
		||||
                    Some(bytes) => {
 | 
			
		||||
                        bridge_handle.to_bridge_sender.send(bytes).await?;
 | 
			
		||||
                    },
 | 
			
		||||
                    None => {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Drop for HostBridge {
 | 
			
		||||
    fn drop(&mut self) {
 | 
			
		||||
        self.task.abort();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -3,6 +3,7 @@ use std::{collections::HashMap, thread, time::Duration};
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use autonet::{AutoNetworkChangeset, AutoNetworkCollector, NetworkMetadata};
 | 
			
		||||
use futures::{future::join_all, TryFutureExt};
 | 
			
		||||
use hbridge::HostBridge;
 | 
			
		||||
use log::warn;
 | 
			
		||||
use tokio::{task::JoinHandle, time::sleep};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
@ -13,6 +14,7 @@ use crate::backend::NetworkBackend;
 | 
			
		||||
pub mod autonet;
 | 
			
		||||
pub mod backend;
 | 
			
		||||
pub mod chandev;
 | 
			
		||||
pub mod hbridge;
 | 
			
		||||
pub mod icmp;
 | 
			
		||||
pub mod nat;
 | 
			
		||||
pub mod pkt;
 | 
			
		||||
@ -23,13 +25,17 @@ pub mod vbridge;
 | 
			
		||||
pub struct NetworkService {
 | 
			
		||||
    pub backends: HashMap<Uuid, JoinHandle<()>>,
 | 
			
		||||
    pub bridge: VirtualBridge,
 | 
			
		||||
    pub hbridge: HostBridge,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl NetworkService {
 | 
			
		||||
    pub fn new() -> Result<NetworkService> {
 | 
			
		||||
    pub async fn new() -> Result<NetworkService> {
 | 
			
		||||
        let bridge = VirtualBridge::new()?;
 | 
			
		||||
        let hbridge = HostBridge::new("krata0".to_string(), &bridge).await?;
 | 
			
		||||
        Ok(NetworkService {
 | 
			
		||||
            backends: HashMap::new(),
 | 
			
		||||
            bridge: VirtualBridge::new()?,
 | 
			
		||||
            bridge,
 | 
			
		||||
            hbridge,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user