bgpkit_parser/models/network/
asn.rs

1#[cfg(feature = "parser")]
2use bytes::{BufMut, Bytes, BytesMut};
3use std::cmp::Ordering;
4use std::fmt::{Debug, Display, Formatter};
5use std::hash::{Hash, Hasher};
6use std::str::FromStr;
7
8/// AS number length: 16 or 32 bits.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub enum AsnLength {
12    Bits16,
13    Bits32,
14}
15
16impl AsnLength {
17    pub const fn is_four_byte(&self) -> bool {
18        match self {
19            AsnLength::Bits16 => false,
20            AsnLength::Bits32 => true,
21        }
22    }
23}
24
25/// ASN -- Autonomous System Number
26#[derive(Clone, Copy, Eq)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28#[cfg_attr(feature = "serde", serde(from = "u32", into = "u32"))]
29pub struct Asn {
30    asn: u32,
31    #[cfg_attr(feature = "serde", serde(skip_serializing, default))]
32    four_byte: bool,
33}
34
35impl Ord for Asn {
36    fn cmp(&self, other: &Self) -> Ordering {
37        self.asn.cmp(&other.asn)
38    }
39}
40
41impl Hash for Asn {
42    fn hash<H: Hasher>(&self, state: &mut H) {
43        self.asn.hash(state);
44    }
45}
46
47impl PartialEq for Asn {
48    fn eq(&self, other: &Self) -> bool {
49        self.asn == other.asn
50    }
51}
52
53impl PartialOrd for Asn {
54    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
55        Some(self.cmp(other))
56    }
57}
58
59impl Asn {
60    pub const RESERVED: Self = Asn::new_16bit(0);
61    #[doc(alias("AS_TRANS"))]
62    pub const TRANSITION: Self = Asn::new_16bit(23456);
63
64    /// Constructs a new 2-octet `Asn`.
65    #[inline]
66    pub const fn new_16bit(asn: u16) -> Self {
67        Asn {
68            asn: asn as u32,
69            four_byte: false,
70        }
71    }
72
73    /// Constructs a new 4-octet `Asn`.
74    #[inline]
75    pub const fn new_32bit(asn: u32) -> Self {
76        Asn {
77            asn,
78            four_byte: true,
79        }
80    }
81
82    /// Gets the size required to store this ASN
83    pub const fn required_len(&self) -> AsnLength {
84        if self.asn <= u16::MAX as u32 {
85            return AsnLength::Bits16;
86        }
87
88        AsnLength::Bits32
89    }
90
91    /// Checks if the given ASN is reserved for private use.
92    ///
93    /// <https://datatracker.ietf.org/doc/rfc7249/>
94    #[inline]
95    pub const fn is_private(&self) -> bool {
96        match self.asn {
97            64512..=65534 => true,           // reserved by RFC6996
98            4200000000..=4294967294 => true, // reserved by RFC6996
99            _ => false,
100        }
101    }
102
103    /// Checks if the given ASN is reserved. This is done by checking if the asn is included
104    /// within IANA's "Special-Purpose AS Numbers" registry. This includes checking against private
105    /// ASN ranges, ASNs reserved for documentation, and ASNs reserved for specific uses by various
106    /// RFCs.
107    ///
108    /// Up to date as of 2023-03-01 (Registry was last updated 2015-08-07).
109    ///
110    /// For additional details see:
111    ///  - <https://datatracker.ietf.org/doc/rfc7249/>
112    ///  - <https://www.iana.org/assignments/iana-as-numbers-special-registry/iana-as-numbers-special-registry.xhtml>
113    #[inline]
114    pub const fn is_reserved(&self) -> bool {
115        match self.asn {
116            0 => true,                       // reserved by RFC7607
117            112 => true,                     // reserved by RFC7534
118            23456 => true,                   // reserved by RFC6793
119            64496..=64511 => true,           // reserved by RFC5398
120            64512..=65534 => true,           // reserved by RFC6996
121            65535 => true,                   // reserved by RFC7300
122            65536..=65551 => true,           // reserved by RFC5398
123            4200000000..=4294967294 => true, // reserved by RFC6996
124            4294967295 => true,              // reserved by RFC7300
125            _ => false,
126        }
127    }
128
129    /// Checks if the given ASN is reserved for use in documentation and sample code.
130    ///
131    /// <https://datatracker.ietf.org/doc/rfc7249/>
132    #[inline]
133    pub const fn is_reserved_for_documentation(&self) -> bool {
134        match self.asn {
135            64496..=64511 => true, // reserved by RFC5398
136            65536..=65551 => true, // reserved by RFC5398
137            _ => false,
138        }
139    }
140
141    /// Return if an ASN is 4 bytes or not.
142    #[inline]
143    pub const fn is_four_byte(&self) -> bool {
144        self.four_byte
145    }
146
147    /// Return AS number as u32.
148    #[inline]
149    pub const fn to_u32(&self) -> u32 {
150        self.asn
151    }
152}
153
154/// Creates an ASN with a value of 0. This is equivalent to [Asn::RESERVED].
155impl Default for Asn {
156    #[inline]
157    fn default() -> Self {
158        Asn::RESERVED
159    }
160}
161
162// *************** //
163// *************** //
164// ASN conversions //
165// *************** //
166// *************** //
167
168impl PartialEq<u32> for Asn {
169    #[inline]
170    fn eq(&self, other: &u32) -> bool {
171        self.asn == *other
172    }
173}
174
175impl From<u32> for Asn {
176    #[inline]
177    fn from(v: u32) -> Self {
178        Asn::new_32bit(v)
179    }
180}
181
182impl From<Asn> for u32 {
183    #[inline]
184    fn from(value: Asn) -> Self {
185        value.asn
186    }
187}
188
189impl From<&Asn> for u32 {
190    #[inline]
191    fn from(value: &Asn) -> Self {
192        value.asn
193    }
194}
195
196impl PartialEq<i32> for Asn {
197    #[inline]
198    fn eq(&self, other: &i32) -> bool {
199        self.asn == *other as u32
200    }
201}
202
203impl From<i32> for Asn {
204    #[inline]
205    fn from(v: i32) -> Self {
206        Asn::new_32bit(v as u32)
207    }
208}
209
210impl From<Asn> for i32 {
211    #[inline]
212    fn from(value: Asn) -> Self {
213        value.asn as i32
214    }
215}
216
217impl From<&Asn> for i32 {
218    #[inline]
219    fn from(value: &Asn) -> Self {
220        value.asn as i32
221    }
222}
223
224impl PartialEq<u16> for Asn {
225    #[inline]
226    fn eq(&self, other: &u16) -> bool {
227        self.asn == *other as u32
228    }
229}
230
231impl From<u16> for Asn {
232    #[inline]
233    fn from(v: u16) -> Self {
234        Asn::new_16bit(v)
235    }
236}
237
238impl From<Asn> for u16 {
239    #[inline]
240    fn from(value: Asn) -> Self {
241        value.asn as u16
242    }
243}
244
245impl From<&Asn> for u16 {
246    #[inline]
247    fn from(value: &Asn) -> Self {
248        value.asn as u16
249    }
250}
251
252impl Display for Asn {
253    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
254        write!(f, "{}", self.asn)
255    }
256}
257
258impl Debug for Asn {
259    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
260        write!(f, "{}", self.asn)
261    }
262}
263
264/// Parse an ASN matching the pattern `(AS)?[0-9]+`.
265impl FromStr for Asn {
266    type Err = <u32 as FromStr>::Err;
267
268    #[inline]
269    fn from_str(mut s: &str) -> Result<Self, Self::Err> {
270        if let Some(number) = s.strip_prefix("AS") {
271            s = number;
272        }
273
274        Ok(Asn::new_32bit(u32::from_str(s)?))
275    }
276}
277
278#[cfg(feature = "parser")]
279impl Asn {
280    pub fn encode(&self) -> Bytes {
281        let mut bytes = BytesMut::with_capacity(if self.four_byte { 4 } else { 2 });
282        match self.four_byte {
283            true => bytes.put_u32(self.asn),
284            false => bytes.put_u16(self.asn as u16),
285        }
286        bytes.freeze()
287    }
288}
289
290#[cfg(test)]
291mod tests {
292    use super::*;
293    #[cfg(feature = "parser")]
294    use crate::parser::ReadUtils;
295    use std::str::FromStr;
296
297    #[cfg(feature = "parser")]
298    #[test]
299    fn test_asn_encode() {
300        let asn = Asn::new_32bit(123);
301        let mut bytes = asn.encode();
302        assert_eq!(123, bytes.read_u32().unwrap());
303    }
304
305    #[test]
306    fn test_asn_is_reserved() {
307        let asn = Asn::new_32bit(0);
308        assert!(asn.is_reserved());
309
310        let asn = Asn::new_32bit(23456);
311        assert!(asn.is_reserved());
312
313        let asn = Asn::new_32bit(64513);
314        assert!(asn.is_reserved());
315
316        let asn = Asn::new_32bit(65535);
317        assert!(asn.is_reserved());
318
319        let asn = Asn::new_32bit(65536);
320        assert!(asn.is_reserved());
321
322        let asn = Asn::new_32bit(4200000000);
323        assert!(asn.is_reserved());
324
325        let asn = Asn::new_32bit(4294967295);
326        assert!(asn.is_reserved());
327
328        let asn = Asn::new_32bit(112);
329        assert!(asn.is_reserved());
330
331        let asn = Asn::new_32bit(400644);
332        assert!(!asn.is_reserved());
333    }
334
335    #[test]
336    fn test_asn_is_reserved_for_documentation() {
337        let asn = Asn::new_32bit(64497);
338        assert!(asn.is_reserved_for_documentation());
339
340        let asn = Asn::new_32bit(65537);
341        assert!(asn.is_reserved_for_documentation());
342
343        let asn = Asn::new_32bit(65535);
344        assert!(!asn.is_reserved_for_documentation());
345    }
346
347    #[test]
348    fn test_asn_is_private() {
349        let asn = Asn::new_32bit(64512);
350        assert!(asn.is_private());
351
352        let asn = Asn::new_32bit(4200000000);
353        assert!(asn.is_private());
354
355        let asn = Asn::new_32bit(4200000001);
356        assert!(asn.is_private());
357
358        let asn = Asn::new_32bit(400644);
359        assert!(!asn.is_private());
360    }
361
362    #[test]
363    fn test_asn_display() {
364        let asn = Asn::from_str("AS12345").unwrap();
365        assert_eq!(12345, asn.to_u32());
366        let asn = Asn::new_32bit(12345);
367        assert_eq!("12345", format!("{asn}"));
368        let asn = Asn::new_32bit(12345);
369        assert_eq!("12345", format!("{asn:?}"));
370    }
371
372    #[test]
373    fn test_default() {
374        assert_eq!(0, Asn::default().asn)
375    }
376
377    #[test]
378    fn test_conversion() {
379        // test conversion from u32/u16/i32 to Asn
380        let asn = Asn::from(12345);
381        assert_eq!(12345, asn.to_u32());
382
383        let asn = Asn::from(12345u16);
384        assert_eq!(12345, asn.to_u32());
385
386        let asn = Asn::from(12345i32);
387        assert_eq!(12345, asn.to_u32());
388
389        // test conversion from Asn to u32/u16/i32
390        let asn = Asn::new_32bit(12345);
391        assert_eq!(12345, u32::from(asn));
392        assert_eq!(12345, u32::from(&asn));
393        assert_eq!(12345, i32::from(asn));
394        assert_eq!(12345, i32::from(&asn));
395        assert_eq!(asn, 12345u16);
396        assert_eq!(asn, 12345u32);
397
398        let asn = Asn::new_16bit(12345);
399        assert_eq!(12345, u16::from(asn));
400        assert_eq!(12345, u16::from(&asn));
401    }
402
403    #[test]
404    fn test_is_four_byte() {
405        let asn = Asn::new_32bit(12345);
406        assert!(asn.is_four_byte());
407        let asn = Asn::new_16bit(12345);
408        assert!(!asn.is_four_byte());
409    }
410
411    #[test]
412    fn test_asn_comparison() {
413        let asn1 = Asn::new_32bit(12345);
414        let asn2 = Asn::new_32bit(12345);
415        assert_eq!(asn1, asn2);
416        assert!(asn1 <= asn2);
417        assert!(asn1 >= asn2);
418
419        let asn3 = Asn::new_32bit(12346);
420        assert!(asn1 < asn3);
421        assert!(asn1 <= asn3);
422    }
423
424    #[test]
425    fn test_required_len() {
426        let asn = Asn::new_32bit(65536);
427        assert_eq!(AsnLength::Bits32, asn.required_len());
428        let asn = Asn::new_32bit(65535);
429        assert_eq!(AsnLength::Bits16, asn.required_len());
430    }
431
432    #[test]
433    #[cfg(feature = "serde")]
434    fn test_asn_length_serialization() {
435        let length_16bit = AsnLength::Bits16;
436        let serialized = serde_json::to_string(&length_16bit).unwrap();
437        assert_eq!(serialized, "\"Bits16\"");
438        let deserialized: AsnLength = serde_json::from_str(&serialized).unwrap();
439        assert_eq!(deserialized, length_16bit);
440
441        let length_32bit = AsnLength::Bits32;
442        let serialized = serde_json::to_string(&length_32bit).unwrap();
443        assert_eq!(serialized, "\"Bits32\"");
444        let deserialized: AsnLength = serde_json::from_str(&serialized).unwrap();
445        assert_eq!(deserialized, length_32bit);
446    }
447}