use super::funejson::Value; /// The address as an unsigned 32-bit number. /// /// Only the strict dotted quad is accepted. The C library's inet_aton also /// reads "010.1.1.1" as octal 8.1.1.1, "0x7f.1" as hex and "127.1" as /// 127.0.0.1; a validator that agrees with one reader and a socket library /// that agrees with the other is how an allow-list gets bypassed, so all of /// those are refused. /// /// # Panics /// Panics when the text is not a strict dotted quad. pub fn parse_ipv4(text: &str) -> i64 { match ipv4_value(text) { Some(value) => value, None => panic!("\"{}\" is not a dotted-quad IPv4 address", text), } } // Exported for is_ipv4 and for capabilities that parse IPv4 text without // wanting a panic; not part of the group's contract. /// The address as a number, or None when the text is not a strict dotted quad. pub fn ipv4_value(text: &str) -> Option { let parts: Vec<&str> = text.split('.').collect(); if parts.len() != 4 { return None; } let mut value: i64 = 0; for part in parts { let bytes = part.as_bytes(); if bytes.is_empty() || bytes.len() > 3 || !bytes.iter().all(|b| b.is_ascii_digit()) { return None; } // A leading zero is where octal readers and decimal readers part company. if bytes.len() > 1 && bytes[0] == b'0' { return None; } let octet = bytes.iter().fold(0i64, |acc, b| acc * 10 + (b - b'0') as i64); if octet > 255 { return None; } value = value * 256 + octet; } Some(value) } pub fn fune_vector(args: &[Value]) -> Value { Value::Int(parse_ipv4(args[0].as_str())) }