482 lines
16 KiB
Rust
482 lines
16 KiB
Rust
use std::{any::TypeId, net::IpAddr, str::FromStr};
|
|
|
|
use cidr::IpCidr;
|
|
|
|
use crate::response::network::{Cidr0Cidr, Network};
|
|
|
|
use super::{string::StringCheck, Check, CheckParams, Checks, GetChecks, GetSubChecks};
|
|
|
|
impl GetChecks for Network {
|
|
fn get_checks(&self, params: CheckParams) -> super::Checks {
|
|
let sub_checks = if params.do_subchecks {
|
|
let mut sub_checks: Vec<Checks> = self
|
|
.common
|
|
.get_sub_checks(params.from_parent(TypeId::of::<Self>()));
|
|
sub_checks.append(
|
|
&mut self
|
|
.object_common
|
|
.get_sub_checks(params.from_parent(TypeId::of::<Self>())),
|
|
);
|
|
if let Some(cidr0) = &self.cidr0_cidrs {
|
|
cidr0.iter().for_each(|cidr| match cidr {
|
|
Cidr0Cidr::V4Cidr(v4) => {
|
|
if v4.v4prefix.is_none() {
|
|
sub_checks.push(Checks {
|
|
rdap_struct: super::RdapStructure::Cidr0,
|
|
items: vec![Check::Cidr0V4PrefixIsAbsent.check_item()],
|
|
sub_checks: vec![],
|
|
})
|
|
}
|
|
if v4.length.is_none() {
|
|
sub_checks.push(Checks {
|
|
rdap_struct: super::RdapStructure::Cidr0,
|
|
items: vec![Check::Cidr0V4LengthIsAbsent.check_item()],
|
|
sub_checks: vec![],
|
|
})
|
|
}
|
|
}
|
|
Cidr0Cidr::V6Cidr(v6) => {
|
|
if v6.v6prefix.is_none() {
|
|
sub_checks.push(Checks {
|
|
rdap_struct: super::RdapStructure::Cidr0,
|
|
items: vec![Check::Cidr0V6PrefixIsAbsent.check_item()],
|
|
sub_checks: vec![],
|
|
})
|
|
}
|
|
if v6.length.is_none() {
|
|
sub_checks.push(Checks {
|
|
rdap_struct: super::RdapStructure::Cidr0,
|
|
items: vec![Check::Cidr0V6LengthIsAbsent.check_item()],
|
|
sub_checks: vec![],
|
|
})
|
|
}
|
|
}
|
|
})
|
|
}
|
|
sub_checks
|
|
} else {
|
|
vec![]
|
|
};
|
|
|
|
let mut items = vec![];
|
|
|
|
if let Some(name) = &self.name {
|
|
if name.is_whitespace_or_empty() {
|
|
items.push(Check::NetworkOrAutnumNameIsEmpty.check_item())
|
|
}
|
|
}
|
|
|
|
if let Some(network_type) = &self.network_type {
|
|
if network_type.is_whitespace_or_empty() {
|
|
items.push(Check::NetworkOrAutnumTypeIsEmpty.check_item())
|
|
}
|
|
}
|
|
|
|
if self.start_address.is_none() || self.end_address.is_none() {
|
|
items.push(Check::IpAddressMissing.check_item())
|
|
}
|
|
|
|
if let Some(start_ip) = &self.start_address {
|
|
let start_addr = IpAddr::from_str(start_ip);
|
|
if start_addr.is_err() {
|
|
items.push(Check::IpAddressMalformed.check_item())
|
|
} else if self.end_address.is_some() {
|
|
let Ok(start_addr) = start_addr else {
|
|
panic!("ip result did not work")
|
|
};
|
|
let Some(end_ip) = &self.end_address else {
|
|
panic!("end address unwrap failed")
|
|
};
|
|
if let Ok(end_addr) = IpAddr::from_str(end_ip) {
|
|
if start_addr > end_addr {
|
|
items.push(Check::IpAddressEndBeforeStart.check_item())
|
|
}
|
|
if let Some(ip_version) = &self.ip_version {
|
|
if (ip_version == "v4" && (start_addr.is_ipv6() || end_addr.is_ipv6()))
|
|
|| (ip_version == "v6" && (start_addr.is_ipv4() || end_addr.is_ipv4()))
|
|
{
|
|
items.push(Check::IpAddressVersionMismatch.check_item())
|
|
} else if ip_version != "v4" && ip_version != "v6" {
|
|
items.push(Check::IpAddressMalformedVersion.check_item())
|
|
}
|
|
}
|
|
let this_network =
|
|
IpCidr::from_str("0.0.0.0/8").expect("incorrect this netowrk cidr");
|
|
if this_network.contains(&start_addr) && this_network.contains(&end_addr) {
|
|
items.push(Check::IpAddressThisNetwork.check_item())
|
|
}
|
|
let private_10 = IpCidr::from_str("10.0.0.0/8").expect("incorrect net 10 cidr");
|
|
let private_172 =
|
|
IpCidr::from_str("172.16.0.0/12").expect("incorrect net 172.16 cidr");
|
|
let private_192 =
|
|
IpCidr::from_str("192.168.0.0/16").expect("incorrect net 192.168 cidr");
|
|
if (private_10.contains(&start_addr) && private_10.contains(&end_addr))
|
|
|| (private_172.contains(&start_addr) && private_172.contains(&end_addr))
|
|
|| (private_192.contains(&start_addr) && private_192.contains(&end_addr))
|
|
{
|
|
items.push(Check::IpAddressPrivateUse.check_item())
|
|
}
|
|
let shared_nat =
|
|
IpCidr::from_str("100.64.0.0/10").expect("incorrect net 100 cidr");
|
|
if shared_nat.contains(&start_addr) && shared_nat.contains(&end_addr) {
|
|
items.push(Check::IpAddressSharedNat.check_item())
|
|
}
|
|
let loopback =
|
|
IpCidr::from_str("127.0.0.0/8").expect("incorrect loopback cidr");
|
|
if loopback.contains(&start_addr) && loopback.contains(&end_addr) {
|
|
items.push(Check::IpAddressLoopback.check_item())
|
|
}
|
|
let linklocal1 =
|
|
IpCidr::from_str("169.254.0.0/16").expect("incorrect linklocal1 cidr");
|
|
let linklocal2 =
|
|
IpCidr::from_str("fe80::/10").expect("incorrect linklocal2 cidr");
|
|
if (linklocal1.contains(&start_addr) && linklocal1.contains(&end_addr))
|
|
|| (linklocal2.contains(&start_addr) && linklocal2.contains(&end_addr))
|
|
{
|
|
items.push(Check::IpAddressLinkLocal.check_item())
|
|
}
|
|
let uniquelocal =
|
|
IpCidr::from_str("fe80::/10").expect("incorrect unique local cidr");
|
|
if uniquelocal.contains(&start_addr) && uniquelocal.contains(&end_addr) {
|
|
items.push(Check::IpAddressUniqueLocal.check_item())
|
|
}
|
|
let doc1 = IpCidr::from_str("192.0.2.0/24").expect("incorrect doc1 cidr");
|
|
let doc2 = IpCidr::from_str("198.51.100.0/24").expect("incorrect doc2 cidr");
|
|
let doc3 = IpCidr::from_str("203.0.113.0/24").expect("incorrect doc3 cidr");
|
|
let doc4 = IpCidr::from_str("2001:db8::/32").expect("incorrect doc4 cidr");
|
|
if (doc1.contains(&start_addr) && doc1.contains(&end_addr))
|
|
|| (doc2.contains(&start_addr) && doc2.contains(&end_addr))
|
|
|| (doc3.contains(&start_addr) && doc3.contains(&end_addr))
|
|
|| (doc4.contains(&start_addr) && doc4.contains(&end_addr))
|
|
{
|
|
items.push(Check::IpAddressDocumentationNet.check_item())
|
|
}
|
|
let reserved =
|
|
IpCidr::from_str("240.0.0.0/4").expect("incorrect reserved cidr");
|
|
if reserved.contains(&start_addr) && reserved.contains(&end_addr) {
|
|
items.push(Check::IpAddressLinkLocal.check_item())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if let Some(end_ip) = &self.end_address {
|
|
let addr = IpAddr::from_str(end_ip);
|
|
if addr.is_err() {
|
|
items.push(Check::IpAddressMalformed.check_item())
|
|
}
|
|
}
|
|
|
|
Checks {
|
|
rdap_struct: super::RdapStructure::IpNetwork,
|
|
items,
|
|
sub_checks,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
|
|
use rstest::rstest;
|
|
|
|
use crate::{
|
|
prelude::{Numberish, ToResponse},
|
|
response::network::{Cidr0Cidr, Network, V4Cidr, V6Cidr},
|
|
};
|
|
|
|
use crate::check::{Check, CheckParams, GetChecks};
|
|
|
|
#[test]
|
|
fn check_network_with_empty_name() {
|
|
// GIVEN
|
|
let mut network = Network::builder()
|
|
.cidr("10.0.0.0/8")
|
|
.build()
|
|
.expect("invalid ip cidr");
|
|
network.name = Some("".to_string());
|
|
let rdap = network.to_response();
|
|
|
|
// WHEN
|
|
let checks = rdap.get_checks(CheckParams::for_rdap(&rdap));
|
|
|
|
// THEN
|
|
dbg!(&checks);
|
|
assert!(checks
|
|
.items
|
|
.iter()
|
|
.any(|c| c.check == Check::NetworkOrAutnumNameIsEmpty));
|
|
}
|
|
|
|
#[test]
|
|
fn check_network_with_empty_type() {
|
|
// GIVEN
|
|
let mut network = Network::builder()
|
|
.cidr("10.0.0.0/8")
|
|
.build()
|
|
.expect("invalid ip cidr");
|
|
network.network_type = Some("".to_string());
|
|
let rdap = network.to_response();
|
|
|
|
// WHEN
|
|
let checks = rdap.get_checks(CheckParams::for_rdap(&rdap));
|
|
|
|
// THEN
|
|
dbg!(&checks);
|
|
assert!(checks
|
|
.items
|
|
.iter()
|
|
.any(|c| c.check == Check::NetworkOrAutnumTypeIsEmpty));
|
|
}
|
|
|
|
#[test]
|
|
fn check_network_with_no_start() {
|
|
// GIVEN
|
|
let mut network = Network::builder()
|
|
.cidr("10.0.0.0/8")
|
|
.build()
|
|
.expect("invalid ip cidr");
|
|
network.start_address = None;
|
|
let rdap = network.to_response();
|
|
|
|
// WHEN
|
|
let checks = rdap.get_checks(CheckParams::for_rdap(&rdap));
|
|
|
|
// THEN
|
|
dbg!(&checks);
|
|
assert!(checks
|
|
.items
|
|
.iter()
|
|
.any(|c| c.check == Check::IpAddressMissing));
|
|
}
|
|
|
|
#[test]
|
|
fn check_network_with_no_end() {
|
|
// GIVEN
|
|
let mut network = Network::builder()
|
|
.cidr("10.0.0.0/8")
|
|
.build()
|
|
.expect("invalid ip cidr");
|
|
network.end_address = None;
|
|
let rdap = network.to_response();
|
|
|
|
// WHEN
|
|
let checks = rdap.get_checks(CheckParams::for_rdap(&rdap));
|
|
|
|
// THEN
|
|
dbg!(&checks);
|
|
assert!(checks
|
|
.items
|
|
.iter()
|
|
.any(|c| c.check == Check::IpAddressMissing));
|
|
}
|
|
|
|
#[test]
|
|
fn check_network_with_bad_start() {
|
|
// GIVEN
|
|
let mut network = Network::builder()
|
|
.cidr("10.0.0.0/8")
|
|
.build()
|
|
.expect("invalid ip cidr");
|
|
network.start_address = Some("____".to_string());
|
|
let rdap = network.to_response();
|
|
|
|
// WHEN
|
|
let checks = rdap.get_checks(CheckParams::for_rdap(&rdap));
|
|
|
|
// THEN
|
|
dbg!(&checks);
|
|
assert!(checks
|
|
.items
|
|
.iter()
|
|
.any(|c| c.check == Check::IpAddressMalformed));
|
|
}
|
|
|
|
#[test]
|
|
fn check_network_with_bad_end() {
|
|
// GIVEN
|
|
let mut network = Network::builder()
|
|
.cidr("10.0.0.0/8")
|
|
.build()
|
|
.expect("invalid ip cidr");
|
|
network.end_address = Some("___".to_string());
|
|
let rdap = network.to_response();
|
|
|
|
// WHEN
|
|
let checks = rdap.get_checks(CheckParams::for_rdap(&rdap));
|
|
|
|
// THEN
|
|
dbg!(&checks);
|
|
assert!(checks
|
|
.items
|
|
.iter()
|
|
.any(|c| c.check == Check::IpAddressMalformed));
|
|
}
|
|
|
|
#[test]
|
|
fn check_network_with_end_before_start() {
|
|
// GIVEN
|
|
let mut network = Network::builder()
|
|
.cidr("10.0.0.0/8")
|
|
.build()
|
|
.expect("invalid ip cidr");
|
|
let swap = network.end_address.clone();
|
|
network.end_address = network.start_address.clone();
|
|
network.start_address = swap;
|
|
let rdap = network.to_response();
|
|
|
|
// WHEN
|
|
let checks = rdap.get_checks(CheckParams::for_rdap(&rdap));
|
|
|
|
// THEN
|
|
dbg!(&checks);
|
|
assert!(checks
|
|
.items
|
|
.iter()
|
|
.any(|c| c.check == Check::IpAddressEndBeforeStart));
|
|
}
|
|
|
|
#[rstest]
|
|
#[case("10.0.0.0/8", "v6")]
|
|
#[case("2000::/64", "v4")]
|
|
fn check_network_with_ip_version(#[case] cidr: &str, #[case] version: &str) {
|
|
// GIVEN
|
|
let mut network = Network::builder()
|
|
.cidr(cidr)
|
|
.build()
|
|
.expect("invalid ip cidr");
|
|
network.ip_version = Some(version.to_string());
|
|
let rdap = network.to_response();
|
|
|
|
// WHEN
|
|
let checks = rdap.get_checks(CheckParams::for_rdap(&rdap));
|
|
|
|
// THEN
|
|
dbg!(&checks);
|
|
assert!(checks
|
|
.items
|
|
.iter()
|
|
.any(|c| c.check == Check::IpAddressVersionMismatch));
|
|
}
|
|
|
|
#[rstest]
|
|
#[case("10.0.0.0/8", "__")]
|
|
#[case("2000::/64", "__")]
|
|
#[case("10.0.0.0/8", "")]
|
|
#[case("2000::/64", "")]
|
|
fn check_network_with_bad_ip_version(#[case] cidr: &str, #[case] version: &str) {
|
|
// GIVEN
|
|
let mut network = Network::builder()
|
|
.cidr(cidr)
|
|
.build()
|
|
.expect("invalid ip cidr");
|
|
network.ip_version = Some(version.to_string());
|
|
let rdap = network.to_response();
|
|
|
|
// WHEN
|
|
let checks = rdap.get_checks(CheckParams::for_rdap(&rdap));
|
|
|
|
// THEN
|
|
dbg!(&checks);
|
|
assert!(checks
|
|
.items
|
|
.iter()
|
|
.any(|c| c.check == Check::IpAddressMalformedVersion));
|
|
}
|
|
|
|
#[test]
|
|
fn check_cidr0_with_v4_prefixex() {
|
|
// GIVEN
|
|
let network = Network::illegal()
|
|
.cidr0_cidrs(vec![Cidr0Cidr::V4Cidr(V4Cidr {
|
|
v4prefix: None,
|
|
length: Some(Numberish::<u8>::from(0)),
|
|
})])
|
|
.build();
|
|
let rdap = network.to_response();
|
|
|
|
// WHEN
|
|
let checks = rdap.get_checks(CheckParams::for_rdap(&rdap));
|
|
|
|
// THEN
|
|
dbg!(&checks);
|
|
assert!(checks
|
|
.sub(crate::check::RdapStructure::Cidr0)
|
|
.expect("Cidr0")
|
|
.items
|
|
.iter()
|
|
.any(|c| c.check == Check::Cidr0V4PrefixIsAbsent));
|
|
}
|
|
|
|
#[test]
|
|
fn check_cidr0_with_v6_prefixex() {
|
|
// GIVEN
|
|
let network = Network::illegal()
|
|
.cidr0_cidrs(vec![Cidr0Cidr::V6Cidr(V6Cidr {
|
|
v6prefix: None,
|
|
length: Some(Numberish::<u8>::from(0)),
|
|
})])
|
|
.build();
|
|
let rdap = network.to_response();
|
|
|
|
// WHEN
|
|
let checks = rdap.get_checks(CheckParams::for_rdap(&rdap));
|
|
|
|
// THEN
|
|
dbg!(&checks);
|
|
assert!(checks
|
|
.sub(crate::check::RdapStructure::Cidr0)
|
|
.expect("Cidr0")
|
|
.items
|
|
.iter()
|
|
.any(|c| c.check == Check::Cidr0V6PrefixIsAbsent));
|
|
}
|
|
|
|
#[test]
|
|
fn check_cidr0_with_v4_length() {
|
|
// GIVEN
|
|
let network = Network::illegal()
|
|
.cidr0_cidrs(vec![Cidr0Cidr::V4Cidr(V4Cidr {
|
|
v4prefix: Some("0.0.0.0".to_string()),
|
|
length: None,
|
|
})])
|
|
.build();
|
|
let rdap = network.to_response();
|
|
|
|
// WHEN
|
|
let checks = rdap.get_checks(CheckParams::for_rdap(&rdap));
|
|
|
|
// THEN
|
|
dbg!(&checks);
|
|
assert!(checks
|
|
.sub(crate::check::RdapStructure::Cidr0)
|
|
.expect("Cidr0")
|
|
.items
|
|
.iter()
|
|
.any(|c| c.check == Check::Cidr0V4LengthIsAbsent));
|
|
}
|
|
|
|
#[test]
|
|
fn check_cidr0_with_v6_length() {
|
|
// GIVEN
|
|
let network = Network::illegal()
|
|
.cidr0_cidrs(vec![Cidr0Cidr::V6Cidr(V6Cidr {
|
|
v6prefix: Some("0.0.0.0".to_string()),
|
|
length: None,
|
|
})])
|
|
.build();
|
|
let rdap = network.to_response();
|
|
|
|
// WHEN
|
|
let checks = rdap.get_checks(CheckParams::for_rdap(&rdap));
|
|
|
|
// THEN
|
|
dbg!(&checks);
|
|
assert!(checks
|
|
.sub(crate::check::RdapStructure::Cidr0)
|
|
.expect("Cidr0")
|
|
.items
|
|
.iter()
|
|
.any(|c| c.check == Check::Cidr0V6LengthIsAbsent));
|
|
}
|
|
}
|