#![doc(html_root_url = "https://docs.rs/postgres-inet/0.15.4")]
#![forbid(
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_extern_crates,
unused_import_braces
)]
extern crate bytes;
#[cfg(feature = "ipnetwork")]
extern crate ipnetwork;
#[cfg(test)]
extern crate postgres;
#[macro_use]
extern crate postgres_types;
mod tests;
use bytes::BytesMut;
use postgres_types::{FromSql, IsNull, ToSql, Type};
use std::error::Error;
use std::fmt;
use std::net::{AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr};
use std::num::ParseIntError;
use std::str::FromStr;
const IPV4_CIDR_FULL: u8 = 32;
const IPV4_ADDRESS_FAMILY: u8 = 2; const IPV4_ADDRESS_SIZE: u8 = 4;
const IPV6_CIDR_FULL: u8 = 128;
const IPV6_ADDRESS_FAMILY: u8 = IPV4_ADDRESS_FAMILY + 1;
const IPV6_ADDRESS_SIZE: u8 = 16;
#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct MaskedIpAddr {
addr: IpAddr,
cidr: u8,
}
impl MaskedIpAddr {
pub fn new<I: Into<IpAddr>>(addr: I, cidr: u8) -> MaskedIpAddr {
let addr = addr.into();
if match addr {
IpAddr::V4(_) => cidr > IPV4_CIDR_FULL,
IpAddr::V6(_) => cidr > IPV6_CIDR_FULL,
} {
panic!("CIDR {} too big for {:?}!", cidr, addr);
}
MaskedIpAddr { addr, cidr }
}
pub fn is_unspecified(&self) -> bool {
self.addr.is_unspecified()
}
pub fn is_loopback(&self) -> bool {
self.addr.is_loopback()
}
pub fn is_multicast(&self) -> bool {
self.addr.is_multicast()
}
pub fn is_ipv4(&self) -> bool {
self.addr.is_ipv4()
}
pub fn is_ipv6(&self) -> bool {
self.addr.is_ipv6()
}
pub fn address(&self) -> IpAddr {
self.addr
}
pub fn cidr(&self) -> u8 {
self.cidr
}
#[deprecated(
since = "0.15.2",
note = "Supported because of historical (and wrong) use of netmask instead of CIDR. \
Use MaskedIpAddr::cidr instead."
)]
pub fn netmask(&self) -> u8 {
self.cidr()
}
pub fn subnet_mask(&self) -> u128 {
fn cidr2mask(full_cidr: u8, cidr: u8, max: u128) -> u128 {
(!((1 << (full_cidr - cidr)) - 1)) & max
}
match self.addr {
IpAddr::V4(_) => cidr2mask(IPV4_CIDR_FULL, self.cidr, u128::from(std::u32::MAX)),
IpAddr::V6(_) => cidr2mask(IPV6_CIDR_FULL, self.cidr, std::u128::MAX),
}
}
pub fn into_inner(self) -> (IpAddr, u8) {
(self.addr, self.cidr)
}
}
impl From<Ipv4Addr> for MaskedIpAddr {
fn from(ipv4: Ipv4Addr) -> MaskedIpAddr {
MaskedIpAddr {
addr: IpAddr::V4(ipv4),
cidr: IPV4_CIDR_FULL,
}
}
}
impl From<Ipv6Addr> for MaskedIpAddr {
fn from(ipv6: Ipv6Addr) -> MaskedIpAddr {
MaskedIpAddr {
addr: IpAddr::V6(ipv6),
cidr: IPV6_CIDR_FULL,
}
}
}
impl From<IpAddr> for MaskedIpAddr {
fn from(ip: IpAddr) -> MaskedIpAddr {
MaskedIpAddr {
cidr: match ip {
IpAddr::V4(_) => IPV4_CIDR_FULL,
IpAddr::V6(_) => IPV6_CIDR_FULL,
},
addr: ip,
}
}
}
impl From<MaskedIpAddr> for IpAddr {
fn from(mip: MaskedIpAddr) -> IpAddr {
mip.addr
}
}
impl From<[u8; 4]> for MaskedIpAddr {
fn from(octets: [u8; 4]) -> MaskedIpAddr {
IpAddr::from(octets).into()
}
}
impl From<[u8; 16]> for MaskedIpAddr {
fn from(octets: [u8; 16]) -> MaskedIpAddr {
IpAddr::from(octets).into()
}
}
impl From<[u16; 8]> for MaskedIpAddr {
fn from(segments: [u16; 8]) -> MaskedIpAddr {
IpAddr::from(segments).into()
}
}
#[cfg(feature = "ipnetwork")]
impl From<ipnetwork::IpNetwork> for MaskedIpAddr {
fn from(ipnetwork: ipnetwork::IpNetwork) -> MaskedIpAddr {
MaskedIpAddr::new(ipnetwork.ip(), ipnetwork.prefix())
}
}
#[cfg(feature = "ipnetwork")]
impl From<MaskedIpAddr> for ipnetwork::IpNetwork {
fn from(mip: MaskedIpAddr) -> ipnetwork::IpNetwork {
ipnetwork::IpNetwork::new(mip.address(), mip.cidr()).unwrap()
}
}
impl fmt::Display for MaskedIpAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.addr {
IpAddr::V4(ipv4) => match self.cidr {
IPV4_CIDR_FULL => ipv4.fmt(f),
_ => write!(f, "{}/{}", ipv4, self.cidr),
},
IpAddr::V6(ipv6) => match self.cidr {
IPV6_CIDR_FULL => ipv6.fmt(f),
_ => write!(f, "{}/{}", ipv6, self.cidr),
},
}
}
}
impl fmt::Debug for MaskedIpAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}/{}", self.addr, self.cidr)
}
}
impl FromSql<'_> for MaskedIpAddr {
fn from_sql(_: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + 'static + Sync + Send>> {
macro_rules! copy_address {
($num_bytes:expr) => {{
const NUM_BYTES: usize = $num_bytes;
let mut octets = [0u8; NUM_BYTES];
octets.copy_from_slice(&raw[4..(NUM_BYTES + 4)]);
IpAddr::from(octets)
}};
}
Ok(MaskedIpAddr {
addr: match raw[3] {
IPV4_ADDRESS_SIZE => copy_address!(IPV4_ADDRESS_SIZE as usize),
IPV6_ADDRESS_SIZE => copy_address!(IPV6_ADDRESS_SIZE as usize),
_ => panic!("Unknown Internet Protocol Version!"),
},
cidr: raw[1],
})
}
fn accepts(ty: &Type) -> bool {
*ty == Type::INET || *ty == Type::CIDR
}
}
impl ToSql for MaskedIpAddr {
fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
fn address_size(addr: IpAddr) -> u8 {
match addr {
IpAddr::V4(_) => IPV4_ADDRESS_SIZE,
IpAddr::V6(_) => IPV6_ADDRESS_SIZE,
}
}
w.reserve(4 + address_size(self.addr) as usize);
w.extend_from_slice(&[
match self.addr {
IpAddr::V4(_) => IPV4_ADDRESS_FAMILY,
IpAddr::V6(_) => IPV6_ADDRESS_FAMILY,
},
self.cidr,
(*ty == Type::CIDR) as u8,
address_size(self.addr),
]);
match self.addr {
IpAddr::V4(ipv4) => w.extend_from_slice(&ipv4.octets()),
IpAddr::V6(ipv6) => w.extend_from_slice(&ipv6.octets()),
};
Ok(IsNull::No)
}
fn accepts(ty: &Type) -> bool {
*ty == Type::INET || *ty == Type::CIDR
}
to_sql_checked!();
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MaskedIpAddrParseError {
Address(AddrParseError),
Netmask(ParseIntError),
Format,
}
impl fmt::Display for MaskedIpAddrParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
MaskedIpAddrParseError::Address(ref e) => e.fmt(f),
MaskedIpAddrParseError::Netmask(ref e) => e.fmt(f),
MaskedIpAddrParseError::Format => f.write_str("invalid CIDR syntax"),
}
}
}
impl Error for MaskedIpAddrParseError {
fn cause(&self) -> Option<&dyn Error> {
match *self {
MaskedIpAddrParseError::Address(ref err) => Some(err),
MaskedIpAddrParseError::Netmask(ref err) => Some(err),
MaskedIpAddrParseError::Format => None,
}
}
}
impl From<AddrParseError> for MaskedIpAddrParseError {
fn from(from: AddrParseError) -> MaskedIpAddrParseError {
MaskedIpAddrParseError::Address(from)
}
}
impl From<ParseIntError> for MaskedIpAddrParseError {
fn from(from: ParseIntError) -> MaskedIpAddrParseError {
MaskedIpAddrParseError::Netmask(from)
}
}
impl FromStr for MaskedIpAddr {
type Err = MaskedIpAddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split('/').collect();
match &parts[..] {
[ip] => Ok(IpAddr::from_str(ip)?.into()),
[ip, cidr] => Ok(MaskedIpAddr::new(IpAddr::from_str(ip)?, cidr.parse()?)),
_ => Err(MaskedIpAddrParseError::Format),
}
}
}