diff --git a/virtweb_backend/Cargo.lock b/virtweb_backend/Cargo.lock index 8104c83..e500f56 100644 --- a/virtweb_backend/Cargo.lock +++ b/virtweb_backend/Cargo.lock @@ -1387,6 +1387,15 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] + [[package]] name = "is-terminal" version = "0.4.9" @@ -2569,6 +2578,7 @@ dependencies = [ "futures", "futures-util", "image", + "ipnetwork", "lazy-regex", "lazy_static", "light-openid", diff --git a/virtweb_backend/Cargo.toml b/virtweb_backend/Cargo.toml index 83ab1a7..7052db2 100644 --- a/virtweb_backend/Cargo.toml +++ b/virtweb_backend/Cargo.toml @@ -39,3 +39,4 @@ rand = "0.8.5" bytes = "1.5.0" tokio = "1.32.0" futures = "0.3.28" +ipnetwork = "0.20.0" \ No newline at end of file diff --git a/virtweb_backend/src/libvirt_lib_structures.rs b/virtweb_backend/src/libvirt_lib_structures.rs index fea5b5b..0e2aece 100644 --- a/virtweb_backend/src/libvirt_lib_structures.rs +++ b/virtweb_backend/src/libvirt_lib_structures.rs @@ -259,6 +259,14 @@ pub struct NetworkDomainXML { pub name: String, } +fn invalid_prefix() -> u32 { + u32::MAX +} + +fn invalid_ip() -> IpAddr { + IpAddr::V4(Ipv4Addr::BROADCAST) +} + /// Network ip information #[derive(serde::Serialize, serde::Deserialize, Debug)] #[serde(rename = "ip")] @@ -267,8 +275,17 @@ pub struct NetworkIPXML { pub family: String, #[serde(rename(serialize = "@address"))] pub address: IpAddr, - #[serde(rename(serialize = "@prefix"))] + /// Network Prefix + #[serde(rename(serialize = "@prefix"), default = "invalid_prefix")] pub prefix: u32, + /// Network Netmask. This field is never serialized, but because we can't know if LibVirt will + /// provide us netmask or prefix, we need to handle both of these fields + #[serde( + rename(serialize = "@netmask"), + default = "invalid_ip", + skip_serializing + )] + pub netmask: IpAddr, pub dhcp: Option, } diff --git a/virtweb_backend/src/libvirt_rest_structures.rs b/virtweb_backend/src/libvirt_rest_structures.rs index 2ba4548..139b0da 100644 --- a/virtweb_backend/src/libvirt_rest_structures.rs +++ b/virtweb_backend/src/libvirt_rest_structures.rs @@ -9,6 +9,7 @@ use crate::libvirt_lib_structures::{ use crate::libvirt_rest_structures::LibVirtStructError::StructureExtraction; use crate::utils::disks_utils::Disk; use crate::utils::files_utils; +use ipnetwork::{Ipv4Network, Ipv6Network}; use lazy_regex::regex; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::ops::{Div, Mul}; @@ -381,6 +382,10 @@ impl NetworkInfo { family: "ipv4".to_string(), address: IpAddr::V4(ipv4.bridge_address), prefix: ipv4.prefix, + netmask: Ipv4Network::new(ipv4.bridge_address, ipv4.prefix as u8) + .unwrap() + .mask() + .into(), dhcp: ipv4.dhcp_range.map(|[start, end]| NetworkDHCPXML { range: NetworkDHCPRangeXML { start: IpAddr::V4(start), @@ -395,6 +400,10 @@ impl NetworkInfo { family: "ipv6".to_string(), address: IpAddr::V6(ipv6.bridge_address), prefix: ipv6.prefix, + netmask: Ipv6Network::new(ipv6.bridge_address, ipv6.prefix as u8) + .unwrap() + .mask() + .into(), dhcp: ipv6.dhcp_range.map(|[start, end]| NetworkDHCPXML { range: NetworkDHCPRangeXML { start: IpAddr::V6(start), @@ -443,7 +452,12 @@ impl NetworkInfo { .find(|i| i.family != "ipv6") .map(|i| IPV4Config { bridge_address: extract_ipv4(i.address), - prefix: i.prefix, + prefix: match i.prefix { + u32::MAX => ipnetwork::ipv4_mask_to_prefix(extract_ipv4(i.netmask)) + .expect("Failed to convert IPv4 netmask to network") + as u32, + p => p, + }, dhcp_range: i .dhcp .as_ref() @@ -455,7 +469,12 @@ impl NetworkInfo { .find(|i| i.family == "ipv6") .map(|i| IPV6Config { bridge_address: extract_ipv6(i.address), - prefix: i.prefix, + prefix: match i.prefix { + u32::MAX => ipnetwork::ipv6_mask_to_prefix(extract_ipv6(i.netmask)) + .expect("Failed to convert IPv6 netmask to network") + as u32, + p => p, + }, dhcp_range: i .dhcp .as_ref()