blob: 06fbb4adb153f0aa97089c79e73bf93807ef483a [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use fidl_fuchsia_net as fidl;
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub struct IpAddress(pub std::net::IpAddr);
impl std::fmt::Display for IpAddress {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let IpAddress(ip_address) = self;
write!(f, "{}", ip_address)
}
}
impl From<fidl::IpAddress> for IpAddress {
fn from(addr: fidl::IpAddress) -> IpAddress {
IpAddress(match addr {
fidl::IpAddress::Ipv4(fidl::IPv4Address { addr }) => addr.into(),
fidl::IpAddress::Ipv6(fidl::IPv6Address { addr }) => addr.into(),
})
}
}
impl Into<fidl::IpAddress> for IpAddress {
fn into(self) -> fidl::IpAddress {
let IpAddress(ip_address) = self;
match ip_address {
std::net::IpAddr::V4(v4addr) => fidl::IpAddress::Ipv4(fidl::IPv4Address {
addr: v4addr.octets(),
}),
std::net::IpAddr::V6(v6addr) => fidl::IpAddress::Ipv6(fidl::IPv6Address {
addr: v6addr.octets(),
}),
}
}
}
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub struct Subnet {
addr: IpAddress,
prefix_len: u8,
}
impl std::fmt::Display for Subnet {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let Self { addr, prefix_len } = self;
write!(f, "{}/{}", addr, prefix_len)
}
}
impl std::str::FromStr for Subnet {
type Err = failure::Error;
// Parse a Subnet from a CIDR-notated IP address.
//
// NB: if we need additional CIDR related functionality in the future,
// we should consider pulling in https://crates.io/crates/cidr
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut pieces = s.split('/');
let addr = pieces
.next()
.expect("String#split should never return an empty iterator")
.parse::<std::net::IpAddr>()?;
let addr_len = match addr {
std::net::IpAddr::V4(_) => 32,
std::net::IpAddr::V6(_) => 128,
};
let validated_prefix = match pieces.next() {
Some(p) => {
let parsed_len = p.parse::<u8>()?;
if parsed_len > addr_len {
Err(failure::format_err!(
"prefix length provided ({} bits) too large. address {} is only {} bits long",
parsed_len,
addr,
addr_len
))
} else {
Ok(parsed_len)
}
}
None => Ok(addr_len),
};
let () = match pieces.next() {
Some(_) => Err(failure::format_err!(
"more than one '/' separator found while attempting to parse CIDR string {}",
s
)),
None => Ok(()),
}?;
let addr = IpAddress(addr);
Ok(Subnet {
addr,
prefix_len: validated_prefix?,
})
}
}
impl From<fidl::Subnet> for Subnet {
fn from(subnet: fidl::Subnet) -> Self {
let fidl::Subnet { addr, prefix_len } = subnet;
let addr = addr.into();
Self { addr, prefix_len }
}
}
impl Into<fidl::Subnet> for Subnet {
fn into(self) -> fidl::Subnet {
let Self { addr, prefix_len } = self;
let addr = addr.into();
fidl::Subnet { addr, prefix_len }
}
}