mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-03 05:10:55 +00:00
network: implement host bridging
This commit is contained in:
parent
2eeb8d5034
commit
25a02f5491
@ -55,6 +55,7 @@ etherparse = "0.14.2"
|
|||||||
async-trait = "0.1.77"
|
async-trait = "0.1.77"
|
||||||
bytes = "1.5.0"
|
bytes = "1.5.0"
|
||||||
path-absolutize = "3.1.1"
|
path-absolutize = "3.1.1"
|
||||||
|
tokio-tun = "0.11.2"
|
||||||
|
|
||||||
[workspace.dependencies.uuid]
|
[workspace.dependencies.uuid]
|
||||||
version = "1.6.1"
|
version = "1.6.1"
|
||||||
|
@ -20,6 +20,7 @@ etherparse = { workspace = true }
|
|||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
uuid = { workspace = true }
|
uuid = { workspace = true }
|
||||||
bytes = { workspace = true }
|
bytes = { workspace = true }
|
||||||
|
tokio-tun = { workspace = true }
|
||||||
|
|
||||||
[dependencies.advmac]
|
[dependencies.advmac]
|
||||||
path = "../libs/advmac"
|
path = "../libs/advmac"
|
||||||
|
@ -10,6 +10,6 @@ struct NetworkArgs {}
|
|||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
env_logger::Builder::from_env(Env::default().default_filter_or("warn")).init();
|
env_logger::Builder::from_env(Env::default().default_filter_or("warn")).init();
|
||||||
let _ = NetworkArgs::parse();
|
let _ = NetworkArgs::parse();
|
||||||
let mut service = NetworkService::new()?;
|
let mut service = NetworkService::new().await?;
|
||||||
service.watch().await
|
service.watch().await
|
||||||
}
|
}
|
||||||
|
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 anyhow::Result;
|
||||||
use autonet::{AutoNetworkChangeset, AutoNetworkCollector, NetworkMetadata};
|
use autonet::{AutoNetworkChangeset, AutoNetworkCollector, NetworkMetadata};
|
||||||
use futures::{future::join_all, TryFutureExt};
|
use futures::{future::join_all, TryFutureExt};
|
||||||
|
use hbridge::HostBridge;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use tokio::{task::JoinHandle, time::sleep};
|
use tokio::{task::JoinHandle, time::sleep};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -13,6 +14,7 @@ use crate::backend::NetworkBackend;
|
|||||||
pub mod autonet;
|
pub mod autonet;
|
||||||
pub mod backend;
|
pub mod backend;
|
||||||
pub mod chandev;
|
pub mod chandev;
|
||||||
|
pub mod hbridge;
|
||||||
pub mod icmp;
|
pub mod icmp;
|
||||||
pub mod nat;
|
pub mod nat;
|
||||||
pub mod pkt;
|
pub mod pkt;
|
||||||
@ -23,13 +25,17 @@ pub mod vbridge;
|
|||||||
pub struct NetworkService {
|
pub struct NetworkService {
|
||||||
pub backends: HashMap<Uuid, JoinHandle<()>>,
|
pub backends: HashMap<Uuid, JoinHandle<()>>,
|
||||||
pub bridge: VirtualBridge,
|
pub bridge: VirtualBridge,
|
||||||
|
pub hbridge: HostBridge,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkService {
|
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 {
|
Ok(NetworkService {
|
||||||
backends: HashMap::new(),
|
backends: HashMap::new(),
|
||||||
bridge: VirtualBridge::new()?,
|
bridge,
|
||||||
|
hbridge,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user