use super::funejson::Value; use super::net_cidr_is_cidr::cidr_block; use super::net_ipv4_format_ipv4::format_ipv4; /// Everything a subnet calculator shows for one IPv4 block. /// /// Host bits in the input are dropped (192.168.1.77/24 describes /// 192.168.1.0/24). A /31 is a point-to-point link with two usable addresses /// and no broadcast (RFC 3021); a /32 is one host. /// /// # Panics /// Panics on a malformed block or an IPv6 block. pub fn cidr_info(cidr: &str) -> CidrInfo { let (version, bits, prefix) = match cidr_block(cidr) { Some(block) => block, None => panic!("\"{}\" is not a CIDR block", cidr), }; if version != 4 { panic!("cidrInfo handles IPv4 blocks only, received \"{}\"", cidr); } let size: i64 = 1 << (32 - prefix); let network = bits[0] - bits[0] % size; let last = network + size - 1; let point_to_point = prefix >= 31; CidrInfo { cidr: format!("{}/{}", format_ipv4(network), prefix), network: format_ipv4(network), prefix, netmask: format_ipv4(4294967296 - size), wildcard: format_ipv4(size - 1), broadcast: if point_to_point { None } else { Some(format_ipv4(last)) }, first_host: format_ipv4(if point_to_point { network } else { network + 1 }), last_host: format_ipv4(if point_to_point { last } else { last - 1 }), host_count: if point_to_point { size } else { size - 2 }, address_count: size, } } pub fn cidr_info_to_value(info: &CidrInfo) -> Value { Value::obj(vec![ ("cidr", Value::str(&info.cidr)), ("network", Value::str(&info.network)), ("prefix", Value::Int(info.prefix)), ("netmask", Value::str(&info.netmask)), ("wildcard", Value::str(&info.wildcard)), ("broadcast", match &info.broadcast { Some(b) => Value::str(b), None => Value::Null, }), ("firstHost", Value::str(&info.first_host)), ("lastHost", Value::str(&info.last_host)), ("hostCount", Value::Int(info.host_count)), ("addressCount", Value::Int(info.address_count)), ]) } pub fn fune_vector(args: &[Value]) -> Value { cidr_info_to_value(&cidr_info(args[0].as_str())) }