mirror of
https://codeberg.org/slatian/service.echoip-slatecave.git
synced 2025-07-17 06:23:29 +02:00
122 lines
3.6 KiB
Rust
122 lines
3.6 KiB
Rust
/*
|
|
* The code in this file should provide a simple way to categorize
|
|
* IP-Address ranges (based on the rust tandard library) and return the
|
|
* result in a template ready format that can be used for custom messages
|
|
* depending on the type of IP-Address.
|
|
*/
|
|
|
|
use std::net::{IpAddr, Ipv4Addr};
|
|
use serde::{Serialize, Deserialize};
|
|
|
|
#[derive(Serialize, Deserialize, Default, PartialEq, Clone)]
|
|
#[serde(rename_all="lowercase")]
|
|
pub enum AddressCast {
|
|
Unspecified,
|
|
#[default]
|
|
Unicast,
|
|
Multicast,
|
|
Broadcast,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Default, PartialEq, Clone)]
|
|
#[serde(rename_all="lowercase")]
|
|
pub enum AddressScope {
|
|
Global,
|
|
Private,
|
|
Shared,
|
|
LinkLocal,
|
|
Loopback,
|
|
Reserved,
|
|
Documentation,
|
|
Nat64,
|
|
#[default]
|
|
Unknown,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Default, Clone)]
|
|
pub struct AddressInfo {
|
|
pub is_v6_address: bool,
|
|
pub cast: AddressCast,
|
|
pub scope: AddressScope,
|
|
}
|
|
|
|
impl AddressInfo {
|
|
pub fn new(address: &IpAddr) -> Self {
|
|
let mut is_v6_address = false;
|
|
let mut address_cast = AddressCast::Unicast;
|
|
let mut address_scope = AddressScope::Unknown;
|
|
match address {
|
|
IpAddr::V4(addr) => {
|
|
let naddr : u32 = (*addr).into();
|
|
let shared_net : u32 = Ipv4Addr::new(100, 64, 0, 0).into();
|
|
let v4_10_mask : u32 = 0xffc00000;
|
|
if addr.is_documentation() {
|
|
address_scope = AddressScope::Documentation;
|
|
//test if this is a shared address
|
|
} else if naddr & v4_10_mask == shared_net {
|
|
address_scope = AddressScope::Shared;
|
|
} else if addr.is_link_local() {
|
|
address_scope = AddressScope::LinkLocal;
|
|
} else if addr.is_private() {
|
|
address_scope = AddressScope::Private;
|
|
} else if addr.is_broadcast() {
|
|
address_cast = AddressCast::Broadcast;
|
|
address_scope = AddressScope::LinkLocal;
|
|
} else {
|
|
address_scope = AddressScope::Global;
|
|
}
|
|
},
|
|
IpAddr::V6(addr) => {
|
|
is_v6_address = true;
|
|
let segments = addr.segments();
|
|
// for std::net these are still nightly only api … 😕
|
|
// Test for unique local addresses fc00::/7
|
|
if segments[0] & 0xfe00 == 0xfc00 {
|
|
address_scope = AddressScope::Private;
|
|
// Test for link local addresses fe80::/10
|
|
} else if segments[0] & 0xffc0 == 0xfe80 {
|
|
address_scope = AddressScope::LinkLocal;
|
|
// Test for the documentation address 2001:db8::/32
|
|
} else if segments[0]==0x2001 && segments[1]==0x0db8 && segments[2]==0 && segments[3]==0 {
|
|
address_scope = AddressScope::Documentation;
|
|
// Test for NAT64 address 64:ff9b::/96
|
|
} else if segments[0]==0x64 && segments[1]==0xff9b {
|
|
address_scope = AddressScope::Nat64;
|
|
// Test for multicase scope
|
|
} else if addr.is_multicast() {
|
|
address_cast = AddressCast::Multicast;
|
|
let cast_type = segments[1] & 0x0f;
|
|
match cast_type {
|
|
1 => address_scope = AddressScope::Loopback,
|
|
2 => address_scope = AddressScope::LinkLocal,
|
|
4 | 5 | 8 => address_scope = AddressScope::Private,
|
|
0xe => address_scope = AddressScope::Global,
|
|
0 | 3 | 0xf => address_scope = AddressScope::Reserved,
|
|
_ => address_scope = AddressScope::Unknown,
|
|
}
|
|
} else if segments[0] & 0xe000 == 0x2000 {
|
|
address_scope = AddressScope::Global;
|
|
}
|
|
|
|
}
|
|
}
|
|
if address.is_loopback() {
|
|
address_scope = AddressScope::Loopback;
|
|
address_cast = AddressCast::Unicast;
|
|
} else if address.is_multicast() {
|
|
address_cast = AddressCast::Multicast;
|
|
} else if address.is_unspecified() {
|
|
address_scope = AddressScope::Unknown;
|
|
address_cast = AddressCast::Unspecified;
|
|
}
|
|
AddressInfo {
|
|
is_v6_address: is_v6_address,
|
|
cast: address_cast,
|
|
scope: address_scope
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|