Skip to main content

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