rpki/src/rtr/payload.rs
2026-03-26 10:04:09 +08:00

297 lines
7.4 KiB
Rust

use std::fmt::Debug;
use std::io;
use std::time::Duration;
use serde::{Deserialize, Serialize};
use crate::data_model::resources::as_resources::Asn;
use crate::data_model::resources::ip_resources::IPAddressPrefix;
use x509_parser::prelude::FromDer;
use x509_parser::x509::SubjectPublicKeyInfo;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
enum PayloadPduType {
Ipv4Prefix = 4,
Ipv6Prefix = 6,
RouterKey = 9,
Aspa = 11,
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct Ski([u8; 20]);
impl AsRef<[u8]> for Ski {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Ski {
pub fn from_bytes(bytes: [u8; 20]) -> Self {
Self(bytes)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct RouteOrigin {
prefix: IPAddressPrefix,
max_length: u8,
asn: Asn,
}
impl RouteOrigin {
pub fn new(prefix: IPAddressPrefix, max_length: u8, asn: Asn) -> Self {
Self {
prefix,
max_length,
asn,
}
}
pub fn prefix(&self) -> &IPAddressPrefix {
&self.prefix
}
pub fn max_length(&self) -> u8 {
self.max_length
}
pub fn asn(&self) -> Asn {
self.asn
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct RouterKey {
subject_key_identifier: Ski,
asn: Asn,
subject_public_key_info: Vec<u8>,
}
impl RouterKey {
pub fn new(subject_key_identifier: Ski, asn: Asn, subject_public_key_info: Vec<u8>) -> Self {
Self {
subject_key_identifier,
asn,
subject_public_key_info,
}
}
pub fn ski(&self) -> Ski {
self.subject_key_identifier
}
pub fn asn(&self) -> Asn {
self.asn
}
pub fn spki(&self) -> &[u8] {
&self.subject_public_key_info
}
pub fn validate(&self) -> Result<(), io::Error> {
if self.asn.into_u32() == 0 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"RouterKey ASN must not be AS0",
));
}
if self.subject_public_key_info.is_empty() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"RouterKey SPKI must not be empty",
));
}
let (rem, _) = SubjectPublicKeyInfo::from_der(&self.subject_public_key_info)
.map_err(|err| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("RouterKey SPKI is not valid DER: {err}"),
)
})?;
if !rem.is_empty() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"RouterKey SPKI DER has trailing bytes: {}",
rem.len()
),
));
}
Ok(())
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct Aspa {
customer_asn: Asn,
provider_asns: Vec<Asn>,
}
impl Aspa {
pub fn new(customer_asn: Asn, mut provider_asns: Vec<Asn>) -> Self {
provider_asns.sort();
provider_asns.dedup();
Self {
customer_asn,
provider_asns,
}
}
pub fn customer_asn(&self) -> Asn {
self.customer_asn
}
pub fn provider_asns(&self) -> &[Asn] {
&self.provider_asns
}
pub fn validate_announcement(&self) -> Result<(), io::Error> {
if self.customer_asn.into_u32() == 0 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"ASPA customer ASN must not be AS0",
));
}
if self.provider_asns.is_empty() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"ASPA announcement must contain at least one provider ASN",
));
}
if self.provider_asns.iter().any(|asn| asn.into_u32() == 0) {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"ASPA provider list must not contain AS0",
));
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum Payload {
/// A route origin.
RouteOrigin(RouteOrigin),
/// A BGPsec router key.
RouterKey(RouterKey),
/// An ASPA unit.
Aspa(Aspa),
}
// Timing
#[derive(Clone, Copy, Debug)]
pub struct Timing {
/// The number of seconds until a client should refresh its data.
pub refresh: u32,
/// The number of seconds a client whould wait before retrying to connect.
pub retry: u32,
/// The number of secionds before data expires if not refreshed.
pub expire: u32
}
impl Timing {
pub const MIN_REFRESH: u32 = 1;
pub const MAX_REFRESH: u32 = 86_400;
pub const MIN_RETRY: u32 = 1;
pub const MAX_RETRY: u32 = 7_200;
pub const MIN_EXPIRE: u32 = 600;
pub const MAX_EXPIRE: u32 = 172_800;
pub const fn new(refresh: u32, retry: u32, expire: u32) -> Self {
Self { refresh, retry, expire }
}
pub fn validate(self) -> Result<(), io::Error> {
if !(Self::MIN_REFRESH..=Self::MAX_REFRESH).contains(&self.refresh) {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"refresh interval {} out of range {}..={}",
self.refresh, Self::MIN_REFRESH, Self::MAX_REFRESH
),
));
}
if !(Self::MIN_RETRY..=Self::MAX_RETRY).contains(&self.retry) {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"retry interval {} out of range {}..={}",
self.retry, Self::MIN_RETRY, Self::MAX_RETRY
),
));
}
if !(Self::MIN_EXPIRE..=Self::MAX_EXPIRE).contains(&self.expire) {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"expire interval {} out of range {}..={}",
self.expire, Self::MIN_EXPIRE, Self::MAX_EXPIRE
),
));
}
if self.expire <= self.refresh {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"expire interval {} must be greater than refresh interval {}",
self.expire, self.refresh
),
));
}
if self.expire <= self.retry {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"expire interval {} must be greater than retry interval {}",
self.expire, self.retry
),
));
}
Ok(())
}
pub fn refresh(self) -> Duration {
Duration::from_secs(u64::from(self.refresh))
}
pub fn retry(self) -> Duration {
Duration::from_secs(u64::from(self.retry))
}
pub fn expire(self) -> Duration {
Duration::from_secs(u64::from(self.expire))
}
}
impl Default for Timing {
fn default() -> Self {
Self {
refresh: 3600,
retry: 600,
expire: 7200,
}
}
}