1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use std::cmp::max;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::net::{Ipv4Addr, Ipv6Addr};

const MASK: u8 = 0b1111_1111;

#[derive(Debug, PartialEq, Clone, Eq, Hash)]
pub enum Address {
    Ipv4(Ipv4Addr),
    Ipv6(Ipv6Addr),
}

impl Display for Address {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        match self {
            Address::Ipv4(ipv4_addr) => ipv4_addr.fmt(f),
            Address::Ipv6(ipv6_addr) => ipv6_addr.fmt(f),
        }
    }
}

impl Address {
    pub fn get_address_number(&self) -> AddressNumber {
        match self {
            Address::Ipv4(_) => AddressNumber::Ipv4,
            Address::Ipv6(_) => AddressNumber::Ipv6,
        }
    }
}

#[derive(Debug, Clone, FromPrimitive, ToPrimitive, PartialEq, Eq, Hash)]
pub enum AddressNumber {
    Ipv4 = 0x0001,
    Ipv6 = 0x0002,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ECSError {
    Ipv4PrefixError(u8),
    Ipv4MaskError(Ipv4Addr, u8),
    Ipv6PrefixError(u8),
    Ipv6MaskError(Ipv6Addr, u8),
}

#[derive(Debug, PartialEq, Clone, Eq, Hash)]
pub struct ECS {
    pub(crate) source_prefix_length: u8,
    pub(crate) scope_prefix_length: u8,
    pub(crate) address: Address,
}

fn check_ipv4_addr(ipv4_addr: &Ipv4Addr, prefix_length: u8) -> Result<(), ECSError> {
    if 32 < prefix_length {
        return Err(ECSError::Ipv4PrefixError(prefix_length));
    } else if 32 == prefix_length {
        return Ok(());
    }

    let octects = ipv4_addr.octets();
    let index = (prefix_length / 8) as usize;
    let remain = prefix_length % 8;

    if (octects[index] & (MASK >> remain)) != 0 {
        return Err(ECSError::Ipv4MaskError(*ipv4_addr, prefix_length));
    }

    let (_, octects_right) = octects.split_at(index + 1);
    for b in octects_right {
        if *b != 0 {
            return Err(ECSError::Ipv4MaskError(*ipv4_addr, prefix_length));
        }
    }

    Ok(())
}

fn check_ipv6_addr(ipv6_addr: &Ipv6Addr, prefix_length: u8) -> Result<(), ECSError> {
    if 128 < prefix_length {
        return Err(ECSError::Ipv6PrefixError(prefix_length));
    } else if 128 == prefix_length {
        return Ok(());
    }

    let octects = ipv6_addr.octets();
    let index = (prefix_length / 8) as usize;
    let remain = prefix_length % 8;

    if (octects[index] & (MASK >> remain)) != 0 {
        return Err(ECSError::Ipv6MaskError(*ipv6_addr, prefix_length));
    }

    let (_, octects_right) = octects.split_at(index + 1);
    for b in octects_right {
        if *b != 0 {
            return Err(ECSError::Ipv6MaskError(*ipv6_addr, prefix_length));
        }
    }

    Ok(())
}

impl ECS {
    pub fn new(
        source_prefix_length: u8,
        scope_prefix_length: u8,
        address: Address,
    ) -> Result<ECS, ECSError> {
        let prefix_length = max(source_prefix_length, scope_prefix_length);
        match &address {
            Address::Ipv4(ipv4_addr) => check_ipv4_addr(ipv4_addr, prefix_length)?,
            Address::Ipv6(ipv6_addr) => check_ipv6_addr(ipv6_addr, prefix_length)?,
        }

        let ecs = ECS {
            source_prefix_length,
            scope_prefix_length,
            address,
        };
        Ok(ecs)
    }
}

impl Display for ECS {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        write!(
            f,
            "{} {} {}",
            self.source_prefix_length, self.scope_prefix_length, self.address
        )
    }
}