use std::{error, fmt, io, iter, str};
use std::fmt::Display;
use std::iter::FromIterator;
use std::net::{AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr};
use std::num::ParseIntError;
use std::str::FromStr;
use bcder::{decode, encode};
use bcder::{BitString, Mode, OctetString, Tag};
use bcder::decode::{ContentError, DecodeError};
use bcder::encode::{Nothing, PrimitiveContent};
use super::super::cert::Overclaim;
use super::super::error::VerificationError;
use super::super::roa::RoaIpAddress;
use super::super::x509::encode_extension;
use super::chain::{Block, OwnedChain, SharedChain};
use super::choice::{InheritedResources, ResourcesChoice};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct IpResources(ResourcesChoice<IpBlocks>);
impl IpResources {
pub fn inherit() -> Self {
IpResources(ResourcesChoice::Inherit)
}
pub fn missing() -> Self {
IpResources(ResourcesChoice::Missing)
}
pub fn blocks(blocks: IpBlocks) -> Self {
if blocks.is_empty() {
IpResources::missing()
}
else {
IpResources(ResourcesChoice::Blocks(blocks))
}
}
pub fn is_inherited(&self) -> bool {
self.0.is_inherited()
}
pub fn is_present(&self) -> bool {
self.0.is_present()
}
pub fn to_blocks(&self) -> Result<IpBlocks, InheritedIpResources> {
self.0.to_blocks().map_err(Into::into)
}
}
impl IpResources {
#[allow(clippy::type_complexity)]
pub fn take_families_from<S: decode::Source>(
cons: &mut decode::Constructed<S>
) -> Result<(Option<Self>, Option<Self>), DecodeError<S::Error>> {
cons.take_sequence(|cons| {
let mut v4 = None;
let mut v6 = None;
while let Some(()) = cons.take_opt_sequence(|cons| {
let af = AddressFamily::take_from(cons)?;
match af {
AddressFamily::Ipv4 => {
if v4.is_some() {
return Err(cons.content_err(
"multiple IPv4 resourcess"
));
}
v4 = Some(Self::take_from(cons, AddressFamily::Ipv4)?);
}
AddressFamily::Ipv6 => {
if v6.is_some() {
return Err(cons.content_err(
"multiple IPv6 resources"
));
}
v6 = Some(Self::take_from(cons, AddressFamily::Ipv6)?);
}
}
Ok(())
})? { }
if v4.is_none() && v6.is_none() {
return Err(cons.content_err(
"no address family in IP resources"
));
}
Ok((v4, v6))
})
}
pub fn take_from<S: decode::Source>(
cons: &mut decode::Constructed<S>,
family: AddressFamily,
) -> Result<Self, DecodeError<S::Error>> {
cons.take_value(|tag, content| {
if tag == Tag::NULL {
content.to_null()?;
Ok(ResourcesChoice::Inherit)
}
else if tag == Tag::SEQUENCE {
IpBlocks::parse_content(content, family)
.map(ResourcesChoice::Blocks)
}
else {
Err(content.content_err("invalid IP resources"))
}
}).map(IpResources)
}
pub fn encode(self) -> impl encode::Values {
match self.0 {
ResourcesChoice::Inherit => {
encode::Choice3::One(().encode())
}
ResourcesChoice::Blocks(blocks) => {
encode::Choice3::Two(blocks.encode())
}
ResourcesChoice::Missing => {
encode::Choice3::Three(encode::sequence(Nothing))
}
}
}
pub fn encode_ref(&self) -> impl encode::Values + '_ {
match self.0 {
ResourcesChoice::Inherit => {
encode::Choice3::One(().encode())
}
ResourcesChoice::Blocks(ref blocks) => {
encode::Choice3::Two(blocks.encode_ref())
}
ResourcesChoice::Missing => {
encode::Choice3::Three(encode::sequence(Nothing))
}
}
}
pub fn encode_family(
&self, family: AddressFamily
) -> impl encode::Values + '_ {
if self.is_present() {
Some(encode::sequence((
family.encode(), self.encode_ref()
)))
}
else {
None
}
}
pub fn encode_extension<'a>(
overclaim: Overclaim,
v4: &'a Self,
v6: &'a Self,
) -> Option<impl encode::Values + 'a> {
if !v4.is_present() && !v6.is_present() {
return None
}
Some(encode_extension(
overclaim.ip_res_id(), true,
encode::sequence((
v4.encode_family(AddressFamily::Ipv4),
v6.encode_family(AddressFamily::Ipv6)
))
))
}
}
#[derive(Clone, Debug)]
pub struct IpResourcesBuilder {
res: Option<IpBlocksBuilder>
}
impl IpResourcesBuilder {
pub fn new() -> Self {
IpResourcesBuilder {
res: Some(IpBlocksBuilder::new())
}
}
pub fn inherit(&mut self) {
self.res = None
}
pub fn blocks<F>(&mut self, build: F)
where F: FnOnce(&mut IpBlocksBuilder) {
if let Some(ref mut builder) = self.res {
build(builder)
}
else {
let mut builder = IpBlocksBuilder::new();
build(&mut builder);
self.res = Some(builder)
}
}
pub fn finalize(self) -> IpResources {
match self.res {
Some(blocks) => IpResources::blocks(blocks.finalize()),
None => IpResources::inherit()
}
}
}
impl Default for IpResourcesBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct IpBlocksForFamily<'a> {
family: AddressFamily,
blocks: &'a IpBlocks
}
impl<'a> IpBlocksForFamily<'a> {
pub fn v4(blocks: &'a IpBlocks) -> Self {
IpBlocksForFamily {
family: AddressFamily::Ipv4,
blocks
}
}
pub fn v6(blocks: &'a IpBlocks) -> Self {
IpBlocksForFamily {
family: AddressFamily::Ipv6,
blocks
}
}
}
impl<'a> fmt::Display for IpBlocksForFamily<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut blocks_iter = self.blocks.iter();
if let Some(el) = blocks_iter.next() {
match self.family {
AddressFamily::Ipv4 => el.fmt_v4(f)?,
AddressFamily::Ipv6 => el.fmt_v6(f)?,
}
}
for el in blocks_iter {
write!(f, ", ")?;
match self.family {
AddressFamily::Ipv4 => el.fmt_v4(f)?,
AddressFamily::Ipv6 => el.fmt_v6(f)?,
}
}
Ok(())
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct IpBlocks(SharedChain<IpBlock>);
impl IpBlocks {
pub fn empty() -> Self {
IpBlocks(SharedChain::empty())
}
pub fn all() -> Self {
IpBlocks(SharedChain::from_owned(
unsafe {
OwnedChain::from_vec_unchecked(vec![
IpBlock::all()
])
}
))
}
pub fn from_resources(
res: IpResources
) -> Result<Self, InheritedIpResources> {
match res.0 {
ResourcesChoice::Missing => Ok(IpBlocks::empty()),
ResourcesChoice::Inherit => Err(InheritedIpResources(())),
ResourcesChoice::Blocks(some) => Ok(some),
}
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item=IpBlock> + '_ {
self.0.iter().copied()
}
pub fn verify_issued(
&self,
res: &IpResources,
mode: Overclaim,
) -> Result<IpBlocks, OverclaimedIpResources> {
match res.0 {
ResourcesChoice::Missing => Ok(Self::empty()),
ResourcesChoice::Inherit => Ok(self.clone()),
ResourcesChoice::Blocks(ref blocks) => {
match mode {
Overclaim::Refuse => {
if self.contains(blocks) {
Ok(blocks.clone())
}
else {
Err(OverclaimedIpResources::new(
self.clone(), blocks.clone(),
))
}
}
Overclaim::Trim => {
Ok(blocks.intersection(self))
}
}
},
}
}
pub fn verify_covered(
&self,
issuer: &IpResources
) -> Result<(), OverclaimedIpResources> {
match issuer.0 {
ResourcesChoice::Missing => {
if self.0.is_empty() {
Ok(())
}
else {
Err(OverclaimedIpResources::new(
IpBlocks::empty(), self.clone(),
))
}
}
ResourcesChoice::Inherit => Ok(()),
ResourcesChoice::Blocks(ref blocks) => {
if self.0.is_encompassed(&blocks.0) {
Ok(())
}
else {
Err(OverclaimedIpResources::new(
blocks.clone(), self.clone(),
))
}
}
}
}
pub fn contains_roa(&self, addr: &RoaIpAddress) -> bool {
let (min, max) = addr.range();
for range in self.iter() {
if range.min() <= min && range.max() >= max {
return true
}
}
false
}
pub fn contains_block(&self, block: impl Into<IpBlock>) -> bool {
let block = block.into();
let (min, max) = (block.min(), block.max());
for range in self.iter() {
if range.min() <= min && range.max() >= max {
return true
}
}
false
}
pub fn intersects_block(&self, block: impl Into<IpBlock>) -> bool {
let block = block.into();
for range in self.iter() {
if range.intersects(&block) {
return true
}
}
false
}
}
impl IpBlocks {
pub fn contains(&self, other: &Self) -> bool {
other.0.is_encompassed(&self.0)
}
pub fn intersection(&self, other: &Self) -> Self {
match self.0.trim(&other.0) {
Ok(()) => self.clone(),
Err(owned) => IpBlocks(SharedChain::from_owned(owned))
}
}
pub fn intersection_assign(&mut self, other: &Self) {
if let Err(owned) = self.0.trim(&other.0) {
self.0 = SharedChain::from_owned(owned)
}
}
pub fn difference(&self, other: &Self) -> Self {
IpBlocks(SharedChain::from_owned(self.0.difference(&other.0)))
}
pub fn union(&self, other: &Self) -> Self {
IpBlocks(
self.0.iter().cloned().chain(other.0.iter().cloned()).collect()
)
}
}
impl IpBlocks {
pub fn take_from<S: decode::Source>(
cons: &mut decode::Constructed<S>
) -> Result<Self, DecodeError<S::Error>> {
cons.take_sequence(|cons| {
Self::parse_cons_content(cons, AddressFamily::Ipv6)
})
}
pub fn take_from_with_family<S: decode::Source>(
cons: &mut decode::Constructed<S>,
family: AddressFamily
) -> Result<Self, DecodeError<S::Error>> {
cons.take_sequence(|cons| {
Self::parse_cons_content(cons, family)
})
}
fn parse_content<S: decode::Source>(
content: &mut decode::Content<S>,
family: AddressFamily,
) -> Result<Self, DecodeError<S::Error>> {
let cons = content.as_constructed()?;
Self::parse_cons_content(cons, family)
}
fn parse_cons_content<S: decode::Source>(
cons: &mut decode::Constructed<S>,
family: AddressFamily,
) -> Result<Self, DecodeError<S::Error>> {
let mut err = None;
let res = iter::repeat_with(||
IpBlock::take_opt_from_with_family(cons, family)
).map(|item| {
match item {
Ok(Some(val)) => Some(val),
Ok(None) => None,
Err(e) => {
err = Some(e);
None
}
}
}).take_while(|item| item.is_some()).map(Option::unwrap).collect();
match err {
Some(err) => Err(err),
None => Ok(IpBlocks(res))
}
}
pub fn encode(self) -> impl encode::Values {
encode::sequence(encode::slice(self.0, |block| block.encode()))
}
pub fn encode_ref(&self) -> impl encode::Values + '_ {
encode::sequence(encode::slice(&self.0, |block| block.encode()))
}
pub fn encode_family(
&self, family: AddressFamily
) -> impl encode::Values + '_ {
encode::sequence((
family.encode(), self.encode_ref()
))
}
pub fn as_v4(&self) -> IpBlocksForFamily {
IpBlocksForFamily::v4(self)
}
pub fn as_v6(&self) -> IpBlocksForFamily {
IpBlocksForFamily::v6(self)
}
}
impl Default for IpBlocks {
fn default() -> Self {
IpBlocks::empty()
}
}
impl FromStr for IpBlocks {
type Err = FromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let family = if s.contains('.') {
AddressFamily::Ipv4
} else {
AddressFamily::Ipv6
};
let mut builder = IpBlocksBuilder::default();
for el in s.split(',') {
let s = el.trim();
if s.is_empty() {
continue
}
match family {
AddressFamily::Ipv4 => {
if let Ok(block) = IpBlock::from_v4_str(s) {
builder.push(block)
} else {
return Err(FromStrError::FamilyMismatch)
}
},
AddressFamily::Ipv6 => {
if let Ok(block) = IpBlock::from_v6_str(s) {
builder.push(block)
} else {
return Err(FromStrError::FamilyMismatch)
}
}
}
}
Ok(builder.finalize())
}
}
impl FromIterator<IpBlock> for IpBlocks {
fn from_iter<I: IntoIterator<Item = IpBlock>>(iter: I) -> Self {
Self(SharedChain::from_iter(iter))
}
}
#[derive(Clone, Debug)]
pub struct IpBlocksBuilder(Vec<IpBlock>);
impl IpBlocksBuilder {
pub fn new() -> Self {
IpBlocksBuilder(Vec::new())
}
pub fn push<T: Into<IpBlock>>(&mut self, block: T) {
self.0.push(block.into())
}
pub fn finalize(self) -> IpBlocks {
self.0.into_iter().collect()
}
}
impl Default for IpBlocksBuilder {
fn default() -> Self {
IpBlocksBuilder::new()
}
}
impl Extend<IpBlock> for IpBlocksBuilder {
fn extend<T>(&mut self, iter: T)
where T: IntoIterator<Item = IpBlock> {
self.0.extend(iter)
}
}
#[derive(Clone, Copy, Debug)]
pub enum IpBlock {
Prefix(Prefix),
Range(AddressRange),
}
impl IpBlock {
pub fn all() -> Self {
IpBlock::Prefix(Prefix::all())
}
pub fn from_v4_str(s: &str) -> Result<Self, FromStrError> {
if let Some(sep) = s.find('/') {
Prefix::from_v4_str_sep(s, sep).map(IpBlock::Prefix)
}
else if let Some(sep) = s.find('-') {
AddressRange::from_v4_str_sep(s, sep).map(IpBlock::Range)
}
else {
let addr = Addr::from(Ipv4Addr::from_str(s)?);
Ok(IpBlock::Range(AddressRange::new(addr, addr.to_max(32))))
}
}
pub fn from_v6_str(s: &str) -> Result<Self, FromStrError> {
if let Some(sep) = s.find('/') {
Prefix::from_v6_str_sep(s, sep).map(IpBlock::Prefix)
}
else if let Some(sep) = s.find('-') {
AddressRange::from_v6_str_sep(s, sep).map(IpBlock::Range)
}
else {
let addr = Ipv6Addr::from_str(s)?.into();
Ok(IpBlock::Range(AddressRange::new(addr, addr)))
}
}
pub fn is_slash_zero(&self) -> bool {
matches!(*self, IpBlock::Prefix(prefix) if prefix.len == 0)
}
pub fn min(&self) -> Addr {
match *self {
IpBlock::Prefix(ref inner) => inner.min(),
IpBlock::Range(ref inner) => inner.min(),
}
}
pub fn max(&self) -> Addr {
match *self {
IpBlock::Prefix(ref inner) => inner.max(),
IpBlock::Range(ref inner) => inner.max(),
}
}
pub fn fmt_v4(self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
IpBlock::Prefix(prefix) => prefix.fmt_v4(f),
IpBlock::Range(range) => range.fmt_v4(f),
}
}
pub fn fmt_v6(self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
IpBlock::Prefix(prefix) => prefix.fmt_v6(f),
IpBlock::Range(range) => range.fmt_v6(f),
}
}
pub fn display_v4(self) -> DisplayV4Block {
DisplayV4Block(self)
}
pub fn display_v6(self) -> DisplayV6Block {
DisplayV6Block(self)
}
}
impl IpBlock {
pub fn take_opt_from<S: decode::Source>(
cons: &mut decode::Constructed<S>
) -> Result<Option<Self>, DecodeError<S::Error>> {
cons.take_opt_value(|tag, content| {
if tag == Tag::BIT_STRING {
Prefix::parse_content(content).map(IpBlock::Prefix)
}
else if tag == Tag::SEQUENCE {
AddressRange::parse_content(content).map(IpBlock::Range)
}
else {
Err(content.content_err("invalid IP resources"))
}
})
}
pub fn take_opt_from_with_family<S: decode::Source>(
cons: &mut decode::Constructed<S>,
family: AddressFamily,
) -> Result<Option<Self>, DecodeError<S::Error>> {
cons.take_opt_value(|tag, content| {
if tag == Tag::BIT_STRING {
Prefix::parse_content_with_family(
content, family
).map(IpBlock::Prefix)
}
else if tag == Tag::SEQUENCE {
AddressRange::parse_content_with_family(
content, family
).map(IpBlock::Range)
}
else {
Err(content.content_err("invalid IP resources"))
}
})
}
pub fn encode(self) -> impl encode::Values {
match self {
IpBlock::Prefix(inner) => {
encode::Choice2::One(inner.encode())
}
IpBlock::Range(inner) => {
encode::Choice2::Two(inner.encode())
}
}
}
}
impl From<Prefix> for IpBlock {
fn from(prefix: Prefix) -> Self {
IpBlock::Prefix(prefix)
}
}
impl From<AddressRange> for IpBlock {
fn from(range: AddressRange) -> Self {
IpBlock::Range(range)
}
}
impl From<(Addr, Addr)> for IpBlock {
fn from(range: (Addr, Addr)) -> Self {
match AddressRange::new(range.0, range.1).into_prefix() {
Ok(prefix) => prefix.into(),
Err(range) => range.into(),
}
}
}
impl str::FromStr for IpBlock {
type Err = FromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Some(sep) = s.find('/') {
Prefix::from_str_sep(s, sep).map(IpBlock::Prefix)
}
else if let Some(sep) = s.find('-') {
AddressRange::from_str_sep(s, sep).map(IpBlock::Range)
}
else {
let (min, max) = match IpAddr::from_str(s)? {
IpAddr::V4(addr) => {
let addr = Addr::from(addr);
(addr, addr.to_max(32))
},
IpAddr::V6(addr) => {
let addr = Addr::from(addr);
(addr, addr)
}
};
Ok(IpBlock::Range(AddressRange::new(min, max)))
}
}
}
impl PartialEq for IpBlock {
fn eq(&self, other: &Self) -> bool {
self.is_equivalent(other)
}
}
impl Eq for IpBlock { }
impl Block for IpBlock {
type Item = Addr;
fn new(min: Self::Item, max: Self::Item) -> Self {
(min, max).into()
}
fn min(&self) -> Self::Item {
self.min()
}
fn max(&self) -> Self::Item {
self.max()
}
fn next(item: Self::Item) -> Option<Self::Item> {
item.0.checked_add(1).map(Addr)
}
fn previous(item: Self::Item) -> Option<Self::Item> {
item.0.checked_sub(1).map(Addr)
}
}
pub struct DisplayV4Block(IpBlock);
impl fmt::Display for DisplayV4Block {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt_v4(fmt)
}
}
pub struct DisplayV6Block(IpBlock);
impl fmt::Display for DisplayV6Block {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt_v6(fmt)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct AddressRange {
min: Addr,
max: Addr,
}
impl AddressRange {
pub fn new(min: Addr, max: Addr) -> Self {
AddressRange { min, max }
}
fn from_str_sep(s: &str, sep: usize) -> Result<Self, FromStrError> {
let min = IpAddr::from_str(&s[..sep])?;
let max = IpAddr::from_str(&s[sep + 1..])?;
match (min.is_ipv4(), max.is_ipv4()) {
(true, true) => {
Ok(Self::new(min.into(), Addr::from(max).to_max(32)))
}
(false, false) => {
Ok(Self::new(min.into(), max.into()))
}
_ => Err(FromStrError::FamilyMismatch)
}
}
fn from_v4_str_sep(s: &str, sep: usize) -> Result<Self, FromStrError> {
Ok(Self::new(
Ipv4Addr::from_str(&s[..sep])?.into(),
Addr::from(Ipv4Addr::from_str(&s[sep + 1..])?).to_max(32)
))
}
pub fn from_v4_str(s: &str) -> Result<Self, FromStrError> {
let sep = s.find('-').ok_or(FromStrError::MissingSeparator)?;
Self::from_v4_str_sep(s, sep)
}
fn from_v6_str_sep(s: &str, sep: usize) -> Result<Self, FromStrError> {
Ok(Self::new(
Ipv6Addr::from_str(&s[..sep])?.into(),
Ipv6Addr::from_str(&s[sep + 1..])?.into()
))
}
pub fn from_v6_str(s: &str) -> Result<Self, FromStrError> {
let sep = s.find('-').ok_or(FromStrError::MissingSeparator)?;
Self::from_v6_str_sep(s, sep)
}
pub fn min(&self) -> Addr {
self.min
}
pub fn max(&self) -> Addr {
self.max
}
pub fn set_min(&mut self, min: Addr) {
if min <= self.max() {
self.min = min
}
else {
panic!("trying to set minimum beyond current maximum");
}
}
pub fn set_max(&mut self, max: Addr) {
if max > self.min() {
self.max = max
}
else {
panic!("trying to set maximum below current minimum");
}
}
pub fn into_prefix(self) -> Result<Prefix, Self> {
let len = (self.min.to_bits() ^ self.max.to_bits()).leading_zeros();
let prefix = Prefix::new(self.min, len as u8);
if prefix.range() == (self.min, self.max) {
Ok(prefix)
}
else {
Err(self)
}
}
pub fn fmt_v4(self, f: &mut fmt::Formatter) -> fmt::Result {
let min = self.min.to_v4();
let max = self.max.to_v4();
if min == max {
min.fmt(f)
} else {
write!(f, "{}-{}", min, max)
}
}
pub fn fmt_v6(self, f: &mut fmt::Formatter) -> fmt::Result {
let min = self.min.to_v6();
let max = self.max.to_v6();
if min == max {
min.fmt(f)
} else {
write!(f, "{}-{}", min, max)
}
}
}
impl AddressRange {
fn parse_content<S: decode::Source>(
content: &mut decode::Content<S>
) -> Result<Self, DecodeError<S::Error>> {
let cons = content.as_constructed()?;
Ok(AddressRange {
min: Prefix::take_from(cons)?.min(),
max: Prefix::take_from(cons)?.max(),
})
}
fn parse_content_with_family<S: decode::Source>(
content: &mut decode::Content<S>,
family: AddressFamily,
) -> Result<Self, DecodeError<S::Error>> {
let cons = content.as_constructed()?;
let min = Self::check_len(
Prefix::take_from(cons)?, family,
).map_err(|err| cons.content_err(err))?;
let max = Self::check_len(
Prefix::take_from(cons)?, family,
).map_err(|err| cons.content_err(err))?;
Ok(AddressRange {
min: min.min(),
max: max.max(),
})
}
#[cfg(not(feature = "compat"))]
fn check_len(
addr: Prefix, family: AddressFamily
) -> Result<Prefix, ContentError> {
if addr.addr_len() > family.max_addr_len() {
Err("invalid range in IP resources".into())
}
else {
Ok(addr)
}
}
#[cfg(feature = "compat")]
fn check_len(
mut addr: Prefix, family: AddressFamily
) -> Result<Prefix, ContentError> {
addr.len = std::cmp::min(addr.len, family.max_addr_len());
Ok(addr)
}
fn min_to_prefix(&self) -> Prefix {
Prefix::new(self.min, 128 - self.min.0.trailing_zeros() as u8)
}
fn max_to_prefix(&self) -> Prefix {
Prefix::new(self.max, 128 - (!self.max.0).trailing_zeros() as u8)
}
pub fn encode(self) -> impl encode::Values {
encode::sequence((
self.min_to_prefix().encode(),
self.max_to_prefix().encode(),
))
}
}
impl From<(Addr, Addr)> for AddressRange {
fn from((min, max): (Addr, Addr)) -> Self {
AddressRange::new(min, max)
}
}
impl From<Prefix> for AddressRange {
fn from(prefix: Prefix) -> Self {
AddressRange::new(prefix.min(), prefix.max())
}
}
impl FromStr for AddressRange {
type Err = FromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let sep = s.find('-').ok_or(FromStrError::MissingSeparator)?;
Self::from_str_sep(s, sep)
}
}
impl Block for AddressRange {
type Item = Addr;
fn new(min: Self::Item, max: Self::Item) -> Self {
Self::new(min, max)
}
fn min(&self) -> Self::Item {
self.min()
}
fn max(&self) -> Self::Item {
self.max()
}
fn next(item: Self::Item) -> Option<Self::Item> {
item.0.checked_add(1).map(Addr)
}
fn previous(item: Self::Item) -> Option<Self::Item> {
item.0.checked_sub(1).map(Addr)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Prefix {
addr: Addr,
len: u8,
}
impl Prefix {
pub fn new<A: Into<Addr>>(addr: A, len: u8) -> Self {
assert!(len <= 128);
Prefix {
addr: addr.into().to_min(len),
len
}
}
pub fn all() -> Self {
Prefix::new(0, 0)
}
pub fn from_bit_string(
src: &BitString
) -> Result<Self, DecodePrefixError> {
if src.octet_len() > 16 {
return Err(DecodePrefixError(()))
}
let mut addr = 0;
for octet in src.octets() {
addr = (addr << 8) | (u128::from(octet))
}
for _ in src.octet_len()..16 {
addr <<= 8;
}
Ok(Self::new(addr, src.bit_len() as u8))
}
fn from_str_sep(s: &str, sep: usize) -> Result<Self, FromStrError> {
let addr = IpAddr::from_str(&s[..sep])?;
let len = u8::from_str(&s[sep + 1..])?;
if addr.is_ipv4() {
if len > 32 {
let _ = u8::from_str("256")?;
}
}
else if len > 128 {
let _ = u8::from_str("256")?;
}
Ok(Prefix::new(addr, len))
}
fn from_v4_str_sep(s: &str, sep: usize) -> Result<Self, FromStrError> {
let addr = Ipv4Addr::from_str(&s[..sep])?;
let len = u8::from_str(&s[sep + 1..])?;
if len > 32 {
let _ = u8::from_str("256")?;
}
Ok(Prefix::new(addr, len))
}
pub fn from_v4_str(s: &str) -> Result<Self, FromStrError> {
let sep = s.find('/').ok_or(FromStrError::MissingSeparator)?;
Self::from_v4_str_sep(s, sep)
}
fn from_v6_str_sep(s: &str, sep: usize) -> Result<Self, FromStrError> {
let addr = Ipv6Addr::from_str(&s[..sep])?;
let len = u8::from_str(&s[sep + 1..])?;
if len > 128 {
let _ = u8::from_str("256")?;
}
Ok(Prefix::new(addr, len))
}
pub fn from_v6_str(s: &str) -> Result<Self, FromStrError> {
let sep = s.find('/').ok_or(FromStrError::MissingSeparator)?;
Self::from_v6_str_sep(s, sep)
}
pub fn addr(self) -> Addr {
self.addr
}
pub fn addr_len(self) -> u8 {
self.len
}
pub fn to_v4(self) -> Ipv4Addr {
self.addr.into()
}
pub fn to_v6(self) -> Ipv6Addr {
self.addr.into()
}
pub fn fmt_v4(self, f: &mut fmt::Formatter) -> fmt::Result {
self.addr.fmt_v4(f)?;
if self.len != 32 {
write!(f, "/{}", self.len)?
}
Ok(())
}
pub fn fmt_v6(self, f: &mut fmt::Formatter) -> fmt::Result {
self.addr.fmt_v6(f)?;
if self.len != 128 {
write!(f, "/{}", self.len)?
}
Ok(())
}
pub fn range(self) -> (Addr, Addr) {
(self.addr, self.addr.to_max(self.len))
}
pub fn min(self) -> Addr {
self.addr
}
pub fn max(self) -> Addr {
self.addr.to_max(self.addr_len())
}
pub fn take_from<S: decode::Source>(
cons: &mut decode::Constructed<S>
) -> Result<Self, DecodeError<S::Error>> {
Self::from_bit_string(
&BitString::take_from(cons)?
).map_err(|err| cons.content_err(err))
}
pub fn parse_content<S: decode::Source>(
content: &mut decode::Content<S>
) -> Result<Self, DecodeError<S::Error>> {
Self::from_bit_string(
&BitString::from_content(content)?
).map_err(|err| content.content_err(err))
}
pub fn parse_content_with_family<S: decode::Source>(
content: &mut decode::Content<S>,
family: AddressFamily,
) -> Result<Self, DecodeError<S::Error>> {
let res = Self::from_bit_string(
&BitString::from_content(content)?
).map_err(|err| content.content_err(err))?;
if res.addr_len() > family.max_addr_len() {
return Err(content.content_err("invalid prefix in IP resources"))
}
Ok(res)
}
}
impl FromStr for Prefix {
type Err = FromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let sep = s.find('/').ok_or(FromStrError::MissingSeparator)?;
Self::from_str_sep(s, sep)
}
}
impl encode::PrimitiveContent for Prefix {
const TAG: Tag = Tag::BIT_STRING;
fn encoded_len(&self, _: Mode) -> usize {
if self.len % 8 == 0 {
self.len as usize / 8 + 1
}
else {
self.len as usize / 8 + 2
}
}
fn write_encoded<W: io::Write>(
&self,
_: Mode,
target: &mut W
) -> Result<(), io::Error> {
let addr = self.addr.to_bytes();
if self.len % 8 == 0 {
target.write_all(&[0])?;
target.write_all(&addr[..(self.len / 8) as usize])
}
else {
target.write_all(&[8 - (self.len % 8)])?;
target.write_all(&addr[..(self.len / 8 + 1) as usize])
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Addr(u128);
impl Addr {
pub fn from_bits(bits: u128) -> Self {
Addr(bits)
}
pub fn from_v4(addr: Ipv4Addr) -> Self {
Addr::from_bits(u128::from(u32::from(addr)) << 96)
}
pub fn from_v6(addr: Ipv6Addr) -> Self {
Addr::from_bits(u128::from(addr))
}
pub fn from_v4_str(s: &str) -> Result<Self, AddrParseError> {
Ipv4Addr::from_str(s).map(Into::into)
}
pub fn from_v6_str(s: &str) -> Result<Self, AddrParseError> {
Ipv6Addr::from_str(s).map(Into::into)
}
pub fn to_bits(self) -> u128 {
self.0
}
pub fn to_v4(self) -> Ipv4Addr {
((self.0 >> 96) as u32).into()
}
pub fn to_v6(self) -> Ipv6Addr {
self.0.into()
}
pub fn to_bytes(self) -> [u8; 16] {
self.0.to_be_bytes()
}
pub fn to_min(self, prefix_len: u8) -> Self {
if prefix_len >= 128 {
self
}
else {
Addr(self.0 & !(!0 >> u32::from(prefix_len)))
}
}
pub fn to_max(self, prefix_len: u8) -> Self {
if prefix_len >= 128 {
self
}
else {
Addr(self.0 | (!0 >> prefix_len as usize))
}
}
pub fn fmt_v4(self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&Ipv4Addr::from(self), f)
}
pub fn fmt_v6(self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&Ipv6Addr::from(self), f)
}
}
impl From<u128> for Addr {
fn from(addr: u128) -> Addr {
Addr::from_bits(addr)
}
}
impl From<Ipv4Addr> for Addr {
fn from(addr: Ipv4Addr) -> Addr {
Addr::from_v4(addr)
}
}
impl From<Ipv6Addr> for Addr {
fn from(addr: Ipv6Addr) -> Addr {
Addr::from_v6(addr)
}
}
impl From<IpAddr> for Addr {
fn from(addr: IpAddr) -> Addr {
match addr {
IpAddr::V4(addr) => Addr::from(addr),
IpAddr::V6(addr) => Addr::from(addr)
}
}
}
impl From<Addr> for u128 {
fn from(addr: Addr) -> u128 {
addr.to_bits()
}
}
impl From<Addr> for Ipv4Addr {
fn from(addr: Addr) -> Ipv4Addr {
addr.to_v4()
}
}
impl From<Addr> for Ipv6Addr {
fn from(addr: Addr) -> Ipv6Addr {
addr.to_v6()
}
}
impl FromStr for Addr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, AddrParseError> {
IpAddr::from_str(s).map(Into::into)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AddressFamily {
Ipv4,
Ipv6
}
impl AddressFamily {
pub fn take_from<S: decode::Source>(
cons: &mut decode::Constructed<S>
) -> Result<Self, DecodeError<S::Error>> {
let octet_string = OctetString::take_from(cons)?;
let afi = Self::decode_octet_string(
octet_string
).map_err(|err| cons.content_err(err))?;
Ok(afi)
}
pub fn take_opt_from<S: decode::Source>(
cons: &mut decode::Constructed<S>
) -> Result<Option<Self>, DecodeError<S::Error>> {
match OctetString::take_opt_from(cons)? {
None => Ok(None),
Some(octet_string) => {
let afi = Self::decode_octet_string(
octet_string
).map_err(|err| cons.content_err(err))?;
Ok(Some(afi))
}
}
}
pub fn skip_opt_in<S: decode::Source>(
cons: &mut decode::Constructed<S>
) -> Result<Option<()>, DecodeError<S::Error>> {
Self::take_opt_from(cons).map(|opt| opt.map(|_| ()))
}
fn decode_octet_string(
octet_string: OctetString
) -> Result<AddressFamily, DecodeFamilyError> {
let mut octets = octet_string.octets();
let first = match octets.next() {
Some(first) => first,
None => return Err(DecodeFamilyError(())),
};
let second = match octets.next() {
Some(second) => second,
None => return Err(DecodeFamilyError(())),
};
if octets.next().is_some() {
return Err(DecodeFamilyError(()))
}
match (first, second) {
(0, 1) => Ok(AddressFamily::Ipv4),
(0, 2) => Ok(AddressFamily::Ipv6),
_ => Err(DecodeFamilyError(())),
}
}
pub fn encode(self) -> impl encode::Values {
OctetString::encode_slice(
match self {
AddressFamily::Ipv4 => b"\x00\x01",
AddressFamily::Ipv6 => b"\x00\x02",
}
)
}
pub fn max_addr_len(self) -> u8 {
match self {
AddressFamily::Ipv4 => 32,
AddressFamily::Ipv6 => 128
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Ipv4Blocks(IpBlocks);
impl Ipv4Blocks {
pub fn empty() -> Self {
Ipv4Blocks(IpBlocks::empty())
}
pub fn all() -> Self {
Ipv4Blocks(IpBlocks::all())
}
pub fn to_ip_resources(&self) -> IpResources {
IpResources::blocks(self.0.clone())
}
}
impl fmt::Display for Ipv4Blocks {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.as_v4().fmt(f)
}
}
impl FromStr for Ipv4Blocks {
type Err = FromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut builder = IpBlocksBuilder::default();
for el in s.split(',') {
let s = el.trim();
if s.is_empty() {
continue
} else if s.contains(':') {
return Err(FromStrError::FamilyMismatch);
} else {
builder.push(IpBlock::from_v4_str(s)?);
}
}
Ok(Ipv4Blocks(builder.finalize()))
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for Ipv4Blocks {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer {
self.to_string().serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Ipv4Blocks {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: serde::Deserializer<'de> {
let string = String::deserialize(deserializer)?;
Ipv4Blocks::from_str(&string).map_err(serde::de::Error::custom)
}
}
impl From<IpBlocks> for Ipv4Blocks {
fn from(blocks: IpBlocks) -> Self {
Ipv4Blocks(blocks)
}
}
impl std::ops::Deref for Ipv4Blocks {
type Target = IpBlocks;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Ipv6Blocks(IpBlocks);
impl Ipv6Blocks {
pub fn empty() -> Self {
Ipv6Blocks(IpBlocks::empty())
}
pub fn all() -> Self {
Ipv6Blocks(IpBlocks::all())
}
pub fn to_ip_resources(&self) -> IpResources {
IpResources::blocks(self.0.clone())
}
}
impl fmt::Display for Ipv6Blocks {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.as_v6().fmt(f)
}
}
impl FromStr for Ipv6Blocks {
type Err = FromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut builder = IpBlocksBuilder::default();
for el in s.split(',') {
let s = el.trim();
if s.is_empty() {
continue
} else if s.contains('.') {
return Err(FromStrError::FamilyMismatch);
} else {
builder.push(IpBlock::from_v6_str(s)?);
}
}
Ok(Ipv6Blocks(builder.finalize()))
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for Ipv6Blocks {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer {
self.to_string().serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Ipv6Blocks {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: serde::Deserializer<'de> {
let string = String::deserialize(deserializer)?;
Ipv6Blocks::from_str(&string).map_err(serde::de::Error::custom)
}
}
impl From<IpBlocks> for Ipv6Blocks {
fn from(blocks: IpBlocks) -> Self {
Ipv6Blocks(blocks)
}
}
impl std::ops::Deref for Ipv6Blocks {
type Target = IpBlocks;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Clone, Copy, Debug)]
pub struct DecodePrefixError(());
impl From<DecodePrefixError> for ContentError {
fn from(_: DecodePrefixError) -> Self {
ContentError::from_static(
"invalid prefix in IP resources"
)
}
}
impl fmt::Display for DecodePrefixError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("invalid prefix in IP resources")
}
}
#[derive(Clone, Copy, Debug)]
pub struct DecodeFamilyError(());
impl From<DecodeFamilyError> for ContentError {
fn from(_: DecodeFamilyError) -> Self {
ContentError::from_static(
"invalid address family in IP resources"
)
}
}
impl fmt::Display for DecodeFamilyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("invalid address family in IP resources")
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum FromStrError {
Addr(AddrParseError),
PrefixLen(ParseIntError),
MissingSeparator,
FamilyMismatch,
BadBlocks,
}
impl From<AddrParseError> for FromStrError {
fn from(err: AddrParseError) -> Self {
FromStrError::Addr(err)
}
}
impl From<ParseIntError> for FromStrError {
fn from(err: ParseIntError) -> Self {
FromStrError::PrefixLen(err)
}
}
impl fmt::Display for FromStrError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
FromStrError::Addr(ref err) => err.fmt(f),
FromStrError::PrefixLen(ref err)
=> write!(f, "bad prefix length: {}", err),
FromStrError::MissingSeparator
=> f.write_str("missing separator"),
FromStrError::FamilyMismatch
=> f.write_str("address family mismatch"),
FromStrError::BadBlocks
=> f.write_str("cannot parse blocks"),
}
}
}
impl error::Error for FromStrError { }
#[derive(Clone, Copy, Debug)]
pub struct InheritedIpResources(());
impl From<InheritedResources> for InheritedIpResources {
fn from(_: InheritedResources) -> InheritedIpResources {
InheritedIpResources(())
}
}
impl fmt::Display for InheritedIpResources {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("inherited IP resources")
}
}
impl error::Error for InheritedIpResources { }
impl From<InheritedIpResources> for VerificationError {
fn from(_: InheritedIpResources) -> Self {
VerificationError::new("inherited IP resources")
}
}
#[derive(Clone, Debug)]
pub struct OverclaimedIpResources {
issuer: IpBlocks,
subject: IpBlocks,
}
impl OverclaimedIpResources {
fn new(issuer: IpBlocks, subject: IpBlocks) -> Self {
OverclaimedIpResources { issuer, subject }
}
pub fn v4(self) -> OverclaimedIpv4Resources {
OverclaimedIpv4Resources(self)
}
pub fn v6(self) -> OverclaimedIpv6Resources {
OverclaimedIpv6Resources(self)
}
}
#[derive(Clone, Debug)]
pub struct OverclaimedIpv4Resources(OverclaimedIpResources);
impl fmt::Display for OverclaimedIpv4Resources {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "overclaimed IPv4 resources: {}",
Ipv4Blocks(self.0.subject.difference(&self.0.issuer))
)
}
}
impl error::Error for OverclaimedIpv4Resources { }
impl From<OverclaimedIpv4Resources> for VerificationError {
fn from(err: OverclaimedIpv4Resources) -> Self {
ContentError::from_boxed(Box::new(err)).into()
}
}
#[derive(Clone, Debug)]
pub struct OverclaimedIpv6Resources(OverclaimedIpResources);
impl fmt::Display for OverclaimedIpv6Resources {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "overclaimed IPv6 resources: {}",
Ipv6Blocks(self.0.subject.difference(&self.0.issuer))
)
}
}
impl error::Error for OverclaimedIpv6Resources { }
impl From<OverclaimedIpv6Resources> for VerificationError {
fn from(err: OverclaimedIpv6Resources) -> Self {
ContentError::from_boxed(Box::new(err)).into()
}
}
#[cfg(test)]
mod test {
use bcder::encode::Values;
use super::*;
#[test]
fn ip_blocks_all() {
assert_eq!(Ipv4Blocks::all().to_string(), "0.0.0.0/0");
assert_eq!(Ipv6Blocks::all().to_string(), "::/0");
}
#[test]
fn ip_blocks_to_v4_str() {
let expected_str = "10.0.0.0, 10.1.0.0-10.1.2.255, 192.168.0.0/16";
let blocks = IpBlocks::from_str(expected_str).unwrap();
assert_eq!(expected_str, &blocks.as_v4().to_string())
}
#[test]
fn ip_blocks_to_v6_str() {
let expected_str = "::1, 2001:db8::/32";
let blocks = IpBlocks::from_str(expected_str).unwrap();
assert_eq!(expected_str, &blocks.as_v6().to_string())
}
#[test]
fn parse_v4range_as_prefix_if_possible() {
let range_str = "10.0.0.0-10.0.0.255";
let prefix_str = "10.0.0.0/24";
let blocks = IpBlocks::from_str(range_str).unwrap();
assert_eq!(prefix_str, &blocks.as_v4().to_string())
}
#[test]
fn parse_v6range_as_prefix_if_possible() {
let range_str = "2001:db8:0:0:0:0:0:0-\
2001:db8:ffff:ffff:ffff:ffff:ffff:ffff";
let prefix_str = "2001:db8::/32";
let blocks = IpBlocks::from_str(range_str).unwrap();
assert_eq!(prefix_str, &blocks.as_v6().to_string())
}
#[test]
fn parse_overlapping_v4() {
let input = "10.20.0.0, 10.0.0.0/16, 10.30.0.0-10.30.0.255, \
10.0.10.0/24";
let output = "10.0.0.0/16, 10.20.0.0, 10.30.0.0/24";
let encoded = [
0x30, 18,
0x03, 3, 0, 10, 0,
0x03, 5, 0, 10, 20, 0, 0,
0x03, 4, 0, 10, 30, 0
];
let blocks = IpBlocks::from_str(input).unwrap();
assert_eq!(
blocks.as_v4().to_string(),
output
);
assert_eq!(
blocks.encode().to_captured(Mode::Der).as_slice(),
&encoded
);
}
#[test]
fn parse_overlapping_v6() {
let input = "2001:db8:0:20::, \
2001:db8:0:10::/64, \
2001:db8:0:30::-2001:db8:0:30::FF, \
2001:db8:0:10::/72";
let output = "2001:db8:0:10::/64, 2001:db8:0:20::, \
2001:db8:0:30::/120";
assert_eq!(
IpBlocks::from_str(input).unwrap().as_v6().to_string(),
output
);
}
#[test]
fn ip_blocks_cannot_parse_mix() {
let input = "10.0.0.0, ::1, 2001:db8::/32";
assert_eq!(
IpBlocks::from_str(input).err(),
Some(FromStrError::FamilyMismatch)
);
}
#[test]
fn ip_blocks_from_empty_str() {
let expected_str = "";
let blocks = IpBlocks::from_str("").unwrap();
assert_eq!(expected_str, blocks.as_v4().to_string());
assert_eq!(expected_str, blocks.as_v6().to_string());
}
#[test]
fn ip_blocks_contains() {
let super_set = IpBlocks::from_str("10.0.0.0/16, 192.168.0.0/16").unwrap();
let same = IpBlocks::from_str("10.0.0.0/16, 192.168.0.0/16").unwrap();
let higher_block = IpBlocks::from_str("192.168.0.0/16").unwrap();
let smaller_left = IpBlocks::from_str("10.0.0.0/17").unwrap();
let smaller_right = IpBlocks::from_str("10.0.0.0/17").unwrap();
let smaller = IpBlocks::from_str("10.0.0.1-10.0.255.254").unwrap();
let bigger_left = IpBlocks::from_str("19.9.9.255-10.0.255.255").unwrap();
let bigger_right = IpBlocks::from_str("19.9.9.255-10.1.0.0").unwrap();
let bigger = IpBlocks::from_str("19.9.9.255-10.1.0.0").unwrap();
assert!(super_set.contains(&same));
assert!(super_set.contains(&higher_block));
assert!(super_set.contains(&smaller_left));
assert!(super_set.contains(&smaller_right));
assert!(super_set.contains(&smaller));
assert!(!super_set.contains(&bigger_left));
assert!(!super_set.contains(&bigger_right));
assert!(!super_set.contains(&bigger ));
}
#[test]
fn ip_blocks_neighbours() {
let super_set = IpBlocks::from_str(
"10.0.0.0-10.0.0.10, 10.0.0.11-10.0.0.20"
).unwrap();
let between = IpBlocks::from_str("10.0.0.5-10.0.0.15").unwrap();
assert!(super_set.contains(&between));
}
#[test]
fn ip_blocks_intersection() {
let this = IpBlocks::from_str("10.0.1.0-10.0.1.255").unwrap();
let other = IpBlocks::from_str("10.0.0.0-10.0.0.255").unwrap();
let expected = IpBlocks::empty();
assert_eq!(this.intersection(&other), expected);
assert_eq!(other.intersection(&this), expected);
let this = IpBlocks::from_str("10.0.1.0/24").unwrap();
let other = IpBlocks::from_str("10.0.0.0-10.0.1.0").unwrap();
let expected = IpBlocks::from_str("10.0.1.0-10.0.1.0").unwrap();
assert_eq!(expected, this.intersection(&other));
assert_eq!(expected, other.intersection(&this));
let this = IpBlocks::from_str("10.0.1.0/24").unwrap();
let other = IpBlocks::from_str("10.0.0.0-10.0.1.27").unwrap();
let expected = IpBlocks::from_str("10.0.1.0-10.0.1.27").unwrap();
assert_eq!(expected, this.intersection(&other));
assert_eq!(expected, other.intersection(&this));
let this = IpBlocks::from_str("10.0.1.0/24").unwrap();
let other = IpBlocks::from_str("10.0.0.0/23").unwrap();
let expected = IpBlocks::from_str("10.0.1.0/24").unwrap();
assert_eq!(expected, this.intersection(&other));
assert_eq!(expected, other.intersection(&this));
let this = IpBlocks::from_str("10.0.1.0/24").unwrap();
let other = IpBlocks::from_str("10.0.0.0-10.0.2.0").unwrap();
let expected = IpBlocks::from_str("10.0.1.0/24").unwrap();
assert_eq!(expected, this.intersection(&other));
assert_eq!(expected, other.intersection(&this));
let this = IpBlocks::from_str("10.0.1.0/24").unwrap();
let other = IpBlocks::from_str("10.0.1.3-10.0.1.98").unwrap();
let expected = IpBlocks::from_str("10.0.1.3-10.0.1.98").unwrap();
assert_eq!(expected, this.intersection(&other));
assert_eq!(expected, other.intersection(&this));
let this = IpBlocks::from_str("10.0.1.0/24").unwrap();
let other = IpBlocks::from_str("10.0.1.0-10.0.1.98").unwrap();
let expected = IpBlocks::from_str("10.0.1.0-10.0.1.98").unwrap();
assert_eq!(expected, this.intersection(&other));
assert_eq!(expected, other.intersection(&this));
let this = IpBlocks::from_str("10.0.1.0/24").unwrap();
let other = IpBlocks::from_str("10.0.1.3-10.0.1.255").unwrap();
let expected = IpBlocks::from_str("10.0.1.3-10.0.1.255").unwrap();
assert_eq!(expected, this.intersection(&other));
assert_eq!(expected, other.intersection(&this));
let this = IpBlocks::from_str("10.0.1.0/24").unwrap();
let other = IpBlocks::from_str("10.0.1.0-10.0.1.255").unwrap();
let expected = IpBlocks::from_str("10.0.1.0-10.0.1.255").unwrap();
assert_eq!(expected, this.intersection(&other));
assert_eq!(expected, other.intersection(&this));
let this = IpBlocks::from_str("10.0.1.0/24").unwrap();
let other = IpBlocks::from_str("10.0.1.3-10.0.2.0").unwrap();
let expected = IpBlocks::from_str("10.0.1.3-10.0.1.255").unwrap();
assert_eq!(
this.intersection(&other).as_v4().to_string(),
expected.as_v4().to_string()
);
assert_eq!(
other.intersection(&this).as_v4().to_string(),
expected.as_v4().to_string()
);
let this = IpBlocks::from_str("10.0.0.0/24").unwrap();
let other = IpBlocks::from_str("10.0.0.255-10.0.1.0").unwrap();
let expected = IpBlocks::from_str("10.0.0.255/32").unwrap();
assert_eq!(
this.intersection(&other).as_v4().to_string(),
expected.as_v4().to_string()
);
assert_eq!(
other.intersection(&this).as_v4().to_string(),
expected.as_v4().to_string()
);
let this = IpBlocks::from_str("10.0.0.0/24").unwrap();
let other = IpBlocks::from_str("10.0.1.0/24").unwrap();
let expected = IpBlocks::empty();
assert_eq!(expected, this.intersection(&other));
assert_eq!(expected, other.intersection(&this));
}
#[test]
fn ip_blocks_difference() {
let v4_left = "10.0.0.0, 10.1.0.0-10.1.2.255, 192.168.0.0/16";
let v4_right = "10.0.0.0/24, 192.168.255.0/24";
let v4_expected = "10.1.0.0-10.1.2.255, 192.168.0.0-192.168.254.255";
let v4_left = IpBlocks::from_str(v4_left).unwrap();
let v4_right = IpBlocks::from_str(v4_right).unwrap();
let v4_expected = IpBlocks::from_str(v4_expected).unwrap();
let v4_found = v4_left.difference(&v4_right);
assert_eq!(v4_expected, v4_found);
}
#[test]
fn ip_block_from_v4_str() {
fn check(s: &str, prefix: bool, min: &str, max: &str) {
let block = IpBlock::from_v4_str(s).unwrap();
let is_prefix = matches!(block, IpBlock::Prefix(_));
assert_eq!(prefix, is_prefix);
assert_eq!(
block.min(),
Addr::from(Ipv4Addr::from_str(min).unwrap()).to_min(32)
);
assert_eq!(
block.max(),
Addr::from(Ipv4Addr::from_str(max).unwrap()).to_max(32)
);
}
check(
"127.0.0.0/8", true,
"127.0.0.0", "127.255.255.255"
);
check(
"127.0.0.0-199.0.0.0", false,
"127.0.0.0", "199.0.0.0"
);
check(
"127.0.0.0", false,
"127.0.0.0", "127.0.0.0"
);
assert!(IpBlock::from_v4_str("127.0.0.0/82").is_err());
assert!(IpBlock::from_v4_str("127.0.0.0/282").is_err());
assert!(IpBlock::from_v4_str("127.0.0.0/-282").is_err());
assert!(IpBlock::from_v4_str("::32/82").is_err());
assert!(IpBlock::from_v4_str("::32-::1").is_err());
}
#[test]
fn ip_block_from_v6_str() {
assert_eq!(
IpBlock::from_v6_str("7f00::").unwrap(),
IpBlock::Range((Addr(127 << 120), Addr(127 << 120)).into())
);
assert_eq!(
IpBlock::from_v6_str("7f00::/8").unwrap(),
IpBlock::Prefix(Prefix::new(Addr(127 << 120), 8))
);
assert_eq!(
IpBlock::from_v6_str("7f00::-c700::").unwrap(),
IpBlock::Range((Addr(127 << 120), Addr(199 << 120)).into())
);
assert!(IpBlock::from_v6_str("f700::/282").is_err());
assert!(IpBlock::from_v6_str("f700:/-282").is_err());
assert!(IpBlock::from_v6_str("127.0.0.0/8").is_err());
assert!(IpBlock::from_v6_str("127.0.0.0-199.0.0.0").is_err());
}
#[test]
fn ip_block_from_str() {
fn check_v4(s: &str, prefix: bool, min: &str, max: &str) {
let block = IpBlock::from_str(s).unwrap();
let is_prefix = matches!(block, IpBlock::Prefix(_));
assert_eq!(prefix, is_prefix);
assert_eq!(
block.min(),
Addr::from(Ipv4Addr::from_str(min).unwrap()).to_min(32)
);
assert_eq!(
block.max(),
Addr::from(Ipv4Addr::from_str(max).unwrap()).to_max(32)
);
}
check_v4(
"127.0.0.0/8", true,
"127.0.0.0", "127.255.255.255"
);
check_v4(
"127.0.0.0-199.0.0.0", false,
"127.0.0.0", "199.0.0.0"
);
check_v4(
"127.0.0.0", false,
"127.0.0.0", "127.0.0.0"
);
assert_eq!(
IpBlock::from_str("7f00::").unwrap(),
IpBlock::Range((Addr(127 << 120), Addr(127 << 120)).into())
);
assert_eq!(
IpBlock::from_str("7f00::/8").unwrap(),
IpBlock::Prefix(Prefix::new(Addr(127 << 120), 8))
);
assert_eq!(
IpBlock::from_str("7f00::-c700::").unwrap(),
IpBlock::Range((Addr(127 << 120), Addr(199 << 120)).into())
);
assert!(IpBlock::from_str("127.0.0.0/82").is_err());
assert!(IpBlock::from_str("127.0.0.0/282").is_err());
assert!(IpBlock::from_str("127.0.0.0/-282").is_err());
assert!(IpBlock::from_str("f700::/282").is_err());
assert!(IpBlock::from_str("f700:/-282").is_err());
}
#[test]
fn block_is_slash_zero() {
assert!(IpBlock::from_str("0.0.0.0/0").unwrap().is_slash_zero());
assert!(IpBlock::from_str("::/0").unwrap().is_slash_zero());
assert!(!IpBlock::from_str("0.0.0.0/10").unwrap().is_slash_zero());
assert!(!IpBlock::from_str("::/10").unwrap().is_slash_zero());
assert!(
!IpBlock::from_str(
"0.0.0.0-255.255.255.255"
).unwrap().is_slash_zero()
);
}
#[test]
fn prefix_encode() {
assert_eq!(
Prefix::new(Ipv4Addr::new(192, 168, 103, 0), 0)
.encode().to_captured(Mode::Der).as_slice(),
b"\x03\x01\x00".as_ref()
);
assert_eq!(
Prefix::new(Ipv4Addr::new(192, 168, 103, 0), 18)
.encode().to_captured(Mode::Der).as_slice(),
b"\x03\x04\x06\xC0\xA8\x40".as_ref()
);
assert_eq!(
Prefix::new(Ipv4Addr::new(192, 168, 103, 0), 16)
.encode().to_captured(Mode::Der).as_slice(),
b"\x03\x03\x00\xC0\xA8".as_ref()
);
assert_eq!(
Prefix::new(Ipv4Addr::new(192, 168, 103, 0), 32)
.encode().to_captured(Mode::Der).as_slice(),
b"\x03\x05\x00\xC0\xA8\x67\x00".as_ref()
);
}
#[test]
fn addr_from() {
assert_eq!(
Addr::from(0x1234_5678_1234_5678),
Addr(0x1234_5678_1234_5678)
);
assert_eq!(
u128::from(Addr(0x1234_5678_1234_5678)),
0x1234_5678_1234_5678
);
assert_eq!(
Addr::from(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
Addr(0x7F00_0001_0000_0000_0000_0000_0000_0000)
);
assert_eq!(
Ipv4Addr::from(Addr(0x7F00_0001_0000_0000_0000_0000_0000_0000)),
Ipv4Addr::new(127, 0, 0, 1)
);
assert_eq!(
Addr::from(IpAddr::V6(Ipv6Addr::new(
0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56
))),
Addr(0x00120034005600780090001200340056)
);
assert_eq!(
Ipv6Addr::from(Addr(0x00120034005600780090001200340056)),
Ipv6Addr::new(
0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56
)
);
}
#[test]
fn addr_to_min_max() {
assert_eq!(
Addr(0x1234_5678_1234_5678_1234_5678_1234_5678).to_min(11).0,
0x1220_0000_0000_0000_0000_0000_0000_0000
);
assert_eq!(
Addr(0x1234_5678_1234_5678_1234_5678_1234_5678).to_max(11).0,
0x123f_ffff_ffff_ffff_ffff_ffff_ffff_ffff
);
}
}
#[cfg(all(test, feature="compat"))]
mod compat_test {
#[test]
fn compat_incorrect_prefix_in_early_cert() {
use bytes::Bytes;
use crate::repository::cert::Cert;
let der = include_bytes!("../../../test-data/compat/res_incorrect.cer");
Cert::decode(Bytes::from_static(der)).unwrap();
}
}