network: implement proper IPv6 networking

This commit is contained in:
Alex Zenla 2024-02-11 07:29:37 +00:00
parent 6773640a39
commit 2c7879ad45
No known key found for this signature in database
GPG Key ID: 067B238899B51269
6 changed files with 51 additions and 12 deletions

View File

@ -350,7 +350,7 @@ impl ContainerInit {
.await?;
if ipv6_ready {
handle
let ipv6_gw_result = handle
.route()
.add()
.v6()
@ -358,7 +358,11 @@ impl ContainerInit {
.output_interface(link.header.index)
.gateway(ipv6_gateway)
.execute()
.await?;
.await;
if let Err(error) = ipv6_gw_result {
warn!("failed to add ipv6 gateway route: {}", error);
}
}
Ok(())

View File

@ -5,7 +5,7 @@ use hyphanet::icmp::{IcmpClient, IcmpProtocol};
#[tokio::main]
async fn main() -> Result<()> {
let client = IcmpClient::new(IcmpProtocol::Icmp6)?;
let client = IcmpClient::new(IcmpProtocol::Icmpv6)?;
let payload: [u8; 4] = [12u8, 14u8, 16u8, 32u8];
let result = client
.ping6(

View File

@ -114,7 +114,7 @@ impl NetworkBackend {
let proxy = Box::new(ProxyNatHandlerFactory::new());
let ipv4 = IpCidr::from_str(&self.ipv4)
.map_err(|_| anyhow!("failed to parse ipv4 cidr: {}", self.ipv4))?;
let ipv6 = IpCidr::from_str(&self.ipv4)
let ipv6 = IpCidr::from_str(&self.ipv6)
.map_err(|_| anyhow!("failed to parse ipv6 cidr: {}", self.ipv6))?;
let addresses: Vec<IpCidr> = vec![ipv4, ipv6];
let mut kdev =

View File

@ -21,15 +21,15 @@ use tokio::{
#[derive(Debug)]
pub enum IcmpProtocol {
Icmp4,
Icmp6,
Icmpv4,
Icmpv6,
}
impl IcmpProtocol {
pub fn to_socket_protocol(&self) -> RawSocketProtocol {
match self {
IcmpProtocol::Icmp4 => RawSocketProtocol::Icmpv4,
IcmpProtocol::Icmp6 => RawSocketProtocol::Icmpv6,
IcmpProtocol::Icmpv4 => RawSocketProtocol::Icmpv4,
IcmpProtocol::Icmpv6 => RawSocketProtocol::Icmpv6,
}
}
}
@ -88,7 +88,7 @@ impl IcmpClient {
let packet = &buffer[0..size];
let (token, reply) = match protocol {
IcmpProtocol::Icmp4 => {
IcmpProtocol::Icmpv4 => {
let sliced = match SlicedPacket::from_ip(packet) {
Ok(sliced) => sliced,
Err(error) => {
@ -126,7 +126,7 @@ impl IcmpClient {
(token, reply)
}
IcmpProtocol::Icmp6 => {
IcmpProtocol::Icmpv6 => {
let Ok(icmpv6) = Icmpv6Slice::from_slice(packet) else {
continue;
};

View File

@ -3,6 +3,8 @@ use async_trait::async_trait;
use etherparse::Ethernet2Slice;
use etherparse::Icmpv4Header;
use etherparse::Icmpv4Type;
use etherparse::Icmpv6Header;
use etherparse::Icmpv6Type;
use etherparse::IpNumber;
use etherparse::IpPayloadSlice;
use etherparse::Ipv4Slice;
@ -220,6 +222,11 @@ impl NatRouter {
.await?;
}
IpNumber::IPV6_ICMP => {
self.process_icmpv6(data, ether, source_addr, dest_addr, ipv6.payload())
.await?;
}
_ => {}
}
@ -295,6 +302,31 @@ impl NatRouter {
Ok(())
}
pub async fn process_icmpv6<'a>(
&mut self,
data: &'a [u8],
ether: &Ethernet2Slice<'a>,
source_addr: IpAddress,
dest_addr: IpAddress,
payload: &IpPayloadSlice<'a>,
) -> Result<()> {
let (header, _) = Icmpv6Header::from_slice(payload.payload)?;
let Icmpv6Type::EchoRequest(_) = header.icmp_type else {
return Ok(());
};
let source = IpEndpoint::new(source_addr, 0);
let dest = IpEndpoint::new(dest_addr, 0);
let key = NatKey {
protocol: NatKeyProtocol::Icmp,
client_mac: EthernetAddress(ether.source()),
local_mac: EthernetAddress(ether.destination()),
client_ip: source,
external_ip: dest,
};
self.process_nat(data, key).await?;
Ok(())
}
pub async fn process_nat(&mut self, data: &[u8], key: NatKey) -> Result<()> {
for cidr in &self.local_cidrs {
if cidr.contains_addr(&key.external_ip.addr) {

View File

@ -48,7 +48,10 @@ impl ProxyIcmpHandler {
context: NatHandlerContext,
rx_receiver: Receiver<Vec<u8>>,
) -> Result<()> {
let client = IcmpClient::new(IcmpProtocol::Icmp4)?;
let client = IcmpClient::new(match context.key.external_ip.addr {
IpAddress::Ipv4(_) => IcmpProtocol::Icmpv4,
IpAddress::Ipv6(_) => IcmpProtocol::Icmpv6,
})?;
tokio::spawn(async move {
if let Err(error) = ProxyIcmpHandler::process(client, rx_receiver, context).await {
warn!("processing of icmp proxy failed: {}", error);
@ -157,7 +160,7 @@ impl ProxyIcmpHandler {
ipv6: &Ipv6Slice<'_>,
client: &IcmpClient,
) -> Result<()> {
if ipv6.header().next_header() != IpNumber::ICMP {
if ipv6.header().next_header() != IpNumber::IPV6_ICMP {
return Ok(());
}