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