1 //! Autonomous System identifier resources.
2 //!
3 //! The types herein are defined in [RFC 3779] for use with certificates in
4 //! general. RFC 6487 specifies how to use them with RPKI certificates. In
5 //! particular, it prohibits the use of RDI values. Additionally, if the
6 //! "inherit" value is not used, the set of identifiers must be non-empty.
7 //!
8 //! AS resources are represented in a certificate by an extension. The data
9 //! in this extension is represented by the [AsResources] enum which
10 //! decomposes into all the other types in this module.
11 //!
12 //! [AsResources]: enum.AsResources.html
13 //! [RFC 3779]: https://tools.ietf.org/html/rfc3779
14 //! [RFC 6487]: https://tools.ietf.org/html/rfc6487
15 
16 use std::{error, fmt, iter, ops};
17 use std::cmp::Ordering;
18 use std::iter::FromIterator;
19 use std::str::FromStr;
20 use bcder::{decode, encode};
21 use bcder::{Tag, xerr};
22 use bcder::encode::{PrimitiveContent, Nothing};
23 use super::super::cert::Overclaim;
24 use super::super::x509::{encode_extension, ValidationError};
25 use super::chain::{Block, SharedChain};
26 use super::choice::ResourcesChoice;
27 
28 
29 //------------ AsResources ---------------------------------------------------
30 
31 /// The AS Resources of an RPKI Certificate.
32 ///
33 /// This type contains the ‘Autonomous System Identifier Delegation Extension’
34 /// as defined in [RFC 3779] in the restricted form specified in [RFC 6487].
35 ///
36 /// This type contains the resources as represented in an RPKI certificate’s
37 /// AS resources extension. This extension provides two options: there can
38 /// be an actual set of AS numbers associated with the certificate – this is
39 /// the `AsResources::Blocks` variant –, or the AS resources of the issuer can
40 /// be inherited – the `AsResources::Inherit` variant.
41 #[derive(Clone, Debug, Eq, PartialEq)]
42 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43 pub struct AsResources(ResourcesChoice<AsBlocks>);
44 
45 impl AsResources {
46     /// Creates a new AsResources with a ResourcesChoice::Inherit
inherit() -> Self47     pub fn inherit() -> Self {
48         AsResources(ResourcesChoice::Inherit)
49     }
50 
51     /// Creates a new AsResources with a ResourceChoice::Missing
missing() -> Self52     pub fn missing() -> Self {
53         AsResources(ResourcesChoice::Missing)
54     }
55 
56     /// Creates a new AsResources for the given blocks.
57     ///
58     /// If the blocks are empty, creates a missing variant in accordance with
59     /// the specification.
blocks(blocks: AsBlocks) -> Self60     pub fn blocks(blocks: AsBlocks) -> Self {
61         if blocks.is_empty() {
62             AsResources::missing()
63         }
64         else {
65             AsResources(ResourcesChoice::Blocks(blocks))
66         }
67     }
68 
69     /// Returns whether the resources are of the inherited variant.
is_inherited(&self) -> bool70     pub fn is_inherited(&self) -> bool {
71         self.0.is_inherited()
72     }
73 
74     /// Returns whether the resources are empty.
75     ///
76     /// Inherited resources are not empty.
is_present(&self) -> bool77     pub fn is_present(&self) -> bool {
78         self.0.is_present()
79     }
80 
81     /// Converts the resources into blocks or returns an error.
to_blocks(&self) -> Result<AsBlocks, ValidationError>82     pub fn to_blocks(&self) -> Result<AsBlocks, ValidationError> {
83         self.0.to_blocks()
84     }
85 }
86 
87 impl AsResources {
88     /// Takes the AS resources from the beginning of an encoded value.
89     ///
90     /// The ASN.1 specification for the `ASIdentifiers` types parsed here is
91     /// given in section 3.2.3 of [RFC 3779] as follows:
92     ///
93     /// ```text
94     /// ASIdentifiers      ::= SEQUENCE {
95     ///     asnum              [0] EXPLICIT AsIdentifierChoice OPTIONAL,
96     ///     rdi                [1] EXPLICIT AsIdentifierChoice OPTIONAL }
97     ///
98     /// AsIdentifierChoice ::= CHOICE {
99     ///     inherit            NULL,
100     ///     asIdsOrRanges      SEQUENCE OF ASIdOrRange }
101     ///
102     /// ASIdOrRange        ::= CHOICE {
103     ///     id                 ASId,
104     ///     range              ASRange }
105     ///
106     /// ASRange            ::= SEQUENCE {
107     ///     min                ASId,
108     ///     max                ASId }
109     ///
110     /// ASId               ::= INTEGER
111     /// ```
112     ///
113     /// Section 4.8.11 of [RFC 6487] limits the `ASIdentifiers` to the
114     /// `asnum` choice. If `asIdsOrRanges` is chosen, it must include a
115     /// non-empty set of AS numbers.
116     ///
117     /// This function implements these limitations. It maps the `id` choice
118     /// of `AsIdOrRange` to a range covering one number in order to keep
119     /// things simpler.
120     ///
121     /// [RFC 3779]: https://tools.ietf.org/html/rfc3779
122     /// [RFC 6487]: https://tools.ietf.org/html/rfc6487
take_from<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<Self, S::Err>123     pub fn take_from<S: decode::Source>(
124         cons: &mut decode::Constructed<S>
125     ) -> Result<Self, S::Err> {
126         cons.take_sequence(|cons| {
127             cons.take_constructed_if(Tag::CTX_0, |cons| {
128                 cons.take_value(|tag, content| {
129                     if tag == Tag::NULL {
130                         content.to_null()?;
131                         Ok(ResourcesChoice::Inherit)
132                     }
133                     else if tag == Tag::SEQUENCE {
134                         AsBlocks::parse_content(content)
135                             .map(ResourcesChoice::Blocks)
136                     }
137                     else {
138                         xerr!(Err(decode::Error::Malformed.into()))
139                     }
140                 })
141             })
142         }).map(AsResources)
143     }
144 
encode(self) -> impl encode::Values145     pub fn encode(self) -> impl encode::Values {
146         encode::sequence(
147             encode::sequence_as(Tag::CTX_0,
148                 match self.0 {
149                     ResourcesChoice::Inherit => {
150                         encode::Choice3::One(().encode())
151                     }
152                     ResourcesChoice::Blocks(blocks) => {
153                         encode::Choice3::Two(
154                             encode::sequence(blocks.encode())
155                         )
156                     }
157                     ResourcesChoice::Missing => {
158                         encode::Choice3::Three(
159                             encode::sequence(Nothing)
160                         )
161                     }
162                 }
163             )
164         )
165     }
166 
encode_ref(&self) -> impl encode::Values + '_167     pub fn encode_ref(&self) -> impl encode::Values + '_ {
168         encode::sequence(
169             encode::sequence_as(Tag::CTX_0,
170                 match self.0 {
171                     ResourcesChoice::Inherit => {
172                         encode::Choice3::One(().encode())
173                     }
174                     ResourcesChoice::Blocks(ref blocks) => {
175                         encode::Choice3::Two(
176                             encode::sequence(blocks.encode_ref())
177                         )
178                     }
179                     ResourcesChoice::Missing => {
180                         encode::Choice3::Three(
181                             encode::sequence(Nothing)
182                         )
183                     }
184                 }
185             )
186         )
187     }
188 
encode_extension( &self, overclaim: Overclaim ) -> impl encode::Values + '_189     pub fn encode_extension(
190         &self, overclaim: Overclaim
191     ) -> impl encode::Values + '_ {
192         if self.0.is_present() {
193             Some(encode_extension(
194                 overclaim.as_res_id(), true, self.encode_ref()
195             ))
196         }
197         else {
198             None
199         }
200     }
201 
202 }
203 
204 //--- Display
205 
206 impl fmt::Display for AsResources {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result207     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
208         self.0.fmt(f)
209     }
210 }
211 
212 //--- FromStr
213 
214 impl FromStr for AsResources {
215     type Err = FromStrError;
216 
from_str(s: &str) -> Result<Self, Self::Err>217     fn from_str(s: &str) -> Result<Self, Self::Err> {
218         if s == "inherit" {
219             Ok(AsResources::inherit())
220         } else {
221             AsBlocks::from_str(s).map(AsResources::blocks)
222         }
223     }
224 }
225 
226 
227 //------------ AsResourcesBuilder --------------------------------------------
228 
229 #[derive(Clone, Debug)]
230 pub struct AsResourcesBuilder {
231     /// The resources.
232     ///
233     /// A value of `None` means inherited resources, an empty builder will be
234     /// transformed into missing resources.
235     res: Option<AsBlocksBuilder>
236 }
237 
238 impl AsResourcesBuilder {
new() -> Self239     pub fn new() -> Self {
240         AsResourcesBuilder {
241             res: Some(AsBlocksBuilder::new())
242         }
243     }
244 
inherit(&mut self)245     pub fn inherit(&mut self) {
246         self.res = None
247     }
248 
blocks<F>(&mut self, build: F) where F: FnOnce(&mut AsBlocksBuilder)249     pub fn blocks<F>(&mut self, build: F)
250     where F: FnOnce(&mut AsBlocksBuilder) {
251         if let Some(ref mut builder) = self.res {
252             build(builder)
253         }
254         else {
255             let mut builder = AsBlocksBuilder::new();
256             build(&mut builder);
257             self.res = Some(builder)
258         }
259     }
260 
finalize(self) -> AsResources261     pub fn finalize(self) -> AsResources {
262         match self.res {
263             Some(blocks) => AsResources::blocks(blocks.finalize()),
264             None => AsResources::inherit(),
265         }
266     }
267 }
268 
269 impl Default for AsResourcesBuilder {
default() -> Self270     fn default() -> Self {
271         Self::new()
272     }
273 }
274 
275 
276 //------------ AsBlocks ------------------------------------------------------
277 
278 /// A possibly empty sequence of consecutive sets of AS numbers.
279 #[derive(Clone, Debug, Eq, PartialEq)]
280 pub struct AsBlocks(SharedChain<AsBlock>);
281 
282 impl AsBlocks {
283     /// Creates empty AS blocks.
empty() -> Self284     pub fn empty() -> Self {
285         AsBlocks(SharedChain::empty())
286     }
287 
288     /// Creates AS blocks from AS resources.
289     ///
290     /// If the AS resources are of the inherited variant, a validation error
291     /// is returned.
from_resources( res: AsResources ) -> Result<Self, ValidationError>292     pub fn from_resources(
293         res: AsResources
294     ) -> Result<Self, ValidationError> {
295         match res.0 {
296             ResourcesChoice::Missing => Ok(AsBlocks::empty()),
297             ResourcesChoice::Inherit => Err(ValidationError),
298             ResourcesChoice::Blocks(some) => Ok(some),
299         }
300     }
301 
302     /// Returns whether the blocks is empty.
is_empty(&self) -> bool303     pub fn is_empty(&self) -> bool {
304         self.0.is_empty()
305     }
306 
307     /// Returns an iterator over the individual AS number blocks.
iter(&self) -> impl Iterator<Item=AsBlock> + '_308     pub fn iter(&self) -> impl Iterator<Item=AsBlock> + '_ {
309         self.0.iter().copied()
310     }
311 
312     /// Validates AS resources issued under these blocks.
validate_issued( &self, res: &AsResources, mode: Overclaim, ) -> Result<AsBlocks, ValidationError>313     pub fn validate_issued(
314         &self,
315         res: &AsResources,
316         mode: Overclaim,
317     ) -> Result<AsBlocks, ValidationError> {
318         match res.0 {
319             ResourcesChoice::Missing => Ok(Self::empty()),
320             ResourcesChoice::Inherit => Ok(self.clone()),
321             ResourcesChoice::Blocks(ref blocks) => {
322                 match mode {
323                     Overclaim::Refuse => {
324                         if blocks.0.is_encompassed(&self.0) {
325                             Ok(blocks.clone())
326                         }
327                         else {
328                             Err(ValidationError)
329                         }
330                     }
331                     Overclaim::Trim => {
332                         match blocks.0.trim(&self.0) {
333                             Ok(()) => Ok(blocks.clone()),
334                             Err(new) => Ok(AsBlocks(new.into()))
335                         }
336                     }
337                 }
338             }
339         }
340     }
341 
342     /// Verifies that these resources are covered by an issuer’s resources.
343     ///
344     /// This is used by bottom-up validation, therefore, issuer resources
345     /// of the inherited kind are considered covering.
verify_covered( &self, issuer: &AsResources ) -> Result<(), ValidationError>346     pub fn verify_covered(
347         &self,
348         issuer: &AsResources
349     ) -> Result<(), ValidationError> {
350         match issuer.0 {
351             ResourcesChoice::Missing => {
352                 if self.0.is_empty() {
353                     Ok(())
354                 }
355                 else {
356                     Err(ValidationError)
357                 }
358             }
359             ResourcesChoice::Inherit => Ok(()),
360             ResourcesChoice::Blocks(ref blocks) => {
361                 if self.0.is_encompassed(&blocks.0) {
362                     Ok(())
363                 }
364                 else {
365                     Err(ValidationError)
366                 }
367             }
368         }
369     }
370 }
371 
372 /// # Set operations
373 ///
374 impl AsBlocks {
375     /// Returns whether this AsBlocks contains the other in its entirety.
contains(&self, other: &Self) -> bool376     pub fn contains(&self, other: &Self) -> bool {
377         other.0.is_encompassed(&self.0)
378     }
379 
380     /// Return the intersection of this AsBlocks and the other. I.e. all
381     /// resources which are found in both.
intersection(&self, other: &Self) -> Self382     pub fn intersection(&self, other: &Self) -> Self {
383         match self.0.trim(&other.0) {
384             Ok(()) => self.clone(),
385             Err(owned) => AsBlocks(SharedChain::from_owned(owned))
386         }
387     }
388 
intersection_assign(&mut self, other: &Self)389     pub fn intersection_assign(&mut self, other: &Self) {
390         if let Err(owned) = self.0.trim(&other.0) {
391             self.0 = SharedChain::from_owned(owned)
392         }
393     }
394 
395     /// Returns a new AsBlocks with the values found in self, but not in other.
difference(&self, other: &Self) -> Self396     pub fn difference(&self, other: &Self) -> Self {
397         AsBlocks(SharedChain::from_owned(self.0.difference(&other.0)))
398     }
399 
400     /// Returns a new AsBlocks with the union of this and the other AsBlocks.
401     ///
402     /// i.e. all resources found in one or both AsBlocks.
union(&self, other: &Self) -> Self403     pub fn union(&self, other: &Self) -> Self {
404         AsBlocks(
405             self.0.iter().cloned().chain(other.0.iter().cloned()).collect()
406         )
407     }
408 }
409 
410 /// # Decoding and Encoding
411 ///
412 impl AsBlocks {
take_from<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<Self, S::Err>413     pub fn take_from<S: decode::Source>(
414         cons: &mut decode::Constructed<S>
415     ) -> Result<Self, S::Err> {
416         cons.take_sequence(Self::parse_cons_content)
417     }
418 
419     /// Parses the content of a AS ID blocks sequence.
parse_content<S: decode::Source>( content: &mut decode::Content<S> ) -> Result<Self, S::Err>420     fn parse_content<S: decode::Source>(
421         content: &mut decode::Content<S>
422     ) -> Result<Self, S::Err> {
423         let cons = content.as_constructed()?;
424         Self::parse_cons_content(cons)
425     }
426 
parse_cons_content<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<Self, S::Err>427     fn parse_cons_content<S: decode::Source>(
428         cons: &mut decode::Constructed<S>
429     ) -> Result<Self, S::Err> {
430         let mut err = None;
431 
432         let res = iter::repeat_with(||
433             AsBlock::take_opt_from(cons)
434         ).map(|item| {
435             match item {
436                 Ok(Some(val)) => Some(val),
437                 Ok(None) => None,
438                 Err(e) => {
439                     err = Some(e);
440                     None
441                 }
442             }
443         }).take_while(|item| item.is_some()).map(Option::unwrap).collect();
444         match err {
445             Some(err) => Err(err),
446             None => Ok(AsBlocks(res))
447         }
448     }
449 
encode(self) -> impl encode::Values450     pub fn encode(self) -> impl encode::Values {
451         encode::slice(self.0, |block| block.encode())
452     }
453 
encode_ref(&self) -> impl encode::Values + '_454     pub fn encode_ref(&self) -> impl encode::Values + '_ {
455         encode::slice(&self.0, |block| block.encode())
456     }
457 }
458 
459 
460 //--- Default
461 
462 impl Default for AsBlocks {
default() -> Self463     fn default() -> Self {
464         AsBlocks::empty()
465     }
466 }
467 
468 
469 //--- FromStr and FromIterator
470 
471 impl FromStr for AsBlocks {
472     type Err = FromStrError;
473 
from_str(s: &str) -> Result<Self, Self::Err>474     fn from_str(s: &str) -> Result<Self, Self::Err> {
475         let mut builder = AsBlocksBuilder::default();
476 
477         for el in s.split(',') {
478             let el = el.trim();
479             if !el.is_empty() {
480                 let block = AsBlock::from_str(el)?;
481                 builder.push(block);
482             }
483         }
484 
485         Ok(builder.finalize())
486     }
487 }
488 
489 impl FromIterator<AsBlock> for AsBlocks {
from_iter<I: IntoIterator<Item = AsBlock>>(iter: I) -> Self490     fn from_iter<I: IntoIterator<Item = AsBlock>>(iter: I) -> Self {
491         Self(SharedChain::from_iter(iter))
492     }
493 }
494 
495 
496 //--- Display
497 
498 impl fmt::Display for AsBlocks {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result499     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
500 
501         let mut iter = self.iter();
502 
503         if let Some(el) = iter.next() {
504             el.fmt(f)?;
505         }
506 
507         for el in iter {
508             write!(f, ", ")?;
509             el.fmt(f)?;
510         }
511 
512         Ok(())
513     }
514 }
515 
516 //--- Serialize and Deserialize
517 
518 #[cfg(feature = "serde")]
519 impl serde::Serialize for AsBlocks {
serialize<S: serde::Serializer>( &self, serializer: S ) -> Result<S::Ok, S::Error>520     fn serialize<S: serde::Serializer>(
521         &self,
522         serializer: S
523     ) -> Result<S::Ok, S::Error> {
524         self.to_string().serialize(serializer)
525     }
526 }
527 
528 #[cfg(feature = "serde")]
529 impl<'de> serde::Deserialize<'de> for AsBlocks {
deserialize<D: serde::Deserializer<'de>>( deserializer: D ) -> Result<Self, D::Error>530     fn deserialize<D: serde::Deserializer<'de>>(
531         deserializer: D
532     ) -> Result<Self, D::Error> {
533         let string = String::deserialize(deserializer)?;
534         Self::from_str(&string).map_err(serde::de::Error::custom)
535     }
536 }
537 
538 
539 //------------ AsBlocksBuilder -----------------------------------------------
540 
541 #[derive(Clone, Debug)]
542 pub struct AsBlocksBuilder(Vec<AsBlock>);
543 
544 impl AsBlocksBuilder {
new() -> Self545     pub fn new() -> Self {
546         AsBlocksBuilder(Vec::new())
547     }
548 
push(&mut self, block: impl Into<AsBlock>)549     pub fn push(&mut self, block: impl Into<AsBlock>) {
550         self.0.push(block.into())
551     }
552 
finalize(self) -> AsBlocks553     pub fn finalize(self) -> AsBlocks {
554         AsBlocks(self.0.into_iter().collect())
555     }
556 }
557 
558 impl Default for AsBlocksBuilder {
default() -> Self559     fn default() -> Self {
560         AsBlocksBuilder::new()
561     }
562 }
563 
564 impl Extend<AsBlock> for AsBlocksBuilder {
extend<T>(&mut self, iter: T) where T: IntoIterator<Item = AsBlock>565     fn extend<T>(&mut self, iter: T)
566     where T: IntoIterator<Item = AsBlock> {
567         self.0.extend(iter)
568     }
569 }
570 
571 
572 //------------ AsBlock -------------------------------------------------------
573 
574 /// A block of consecutive AS numbers.
575 #[derive(Clone, Copy, Debug)]
576 pub enum AsBlock {
577     /// The block is a single AS number.
578     Id(AsId),
579 
580     /// The block is a range of AS numbers.
581     Range(AsRange),
582 }
583 
584 impl AsBlock {
585     /// The smallest AS number that is part of this block.
min(&self) -> AsId586     pub fn min(&self) -> AsId {
587         match *self {
588             AsBlock::Id(id) => id,
589             AsBlock::Range(ref range) => range.min(),
590         }
591     }
592 
593     /// The largest AS number that is still part of this block.
max(&self) -> AsId594     pub fn max(&self) -> AsId {
595         match *self {
596             AsBlock::Id(id) => id,
597             AsBlock::Range(ref range) => range.max(),
598         }
599     }
600 
601     /// Sets a new minimum AS number.
602     ///
603     /// # Panics
604     ///
605     /// If you try to set the minimum to value larger than the current
606     /// maximum, the method will panic.
set_min(&mut self, id: AsId)607     pub fn set_min(&mut self, id: AsId) {
608         match id.cmp(&self.max()) {
609             Ordering::Less => {
610                 *self = AsBlock::Range(AsRange::new(id, self.max()))
611             }
612             Ordering::Equal => {
613                 *self = AsBlock::Id(id)
614             }
615             Ordering::Greater => {
616                 panic!("trying to set minimum beyond current maximum");
617             }
618         }
619     }
620 
621     /// Sets a new maximum AS number.
622     ///
623     /// # Panics
624     ///
625     /// If you try to set the minimum to value smaller than the current
626     /// minimum, the method will panic.
set_max(&mut self, id: AsId)627     pub fn set_max(&mut self, id: AsId) {
628         match id.cmp(&self.min()) {
629             Ordering::Greater => {
630                 *self = AsBlock::Range(AsRange::new(self.min(), id))
631             }
632             Ordering::Equal => {
633                 *self = AsBlock::Id(id)
634             }
635             Ordering::Less => {
636                 panic!("trying to set maximum below current minimum");
637             }
638         }
639     }
640 
641     /// Returns whether this is a block covering all AS Ids.
is_whole_range(&self) -> bool642     pub fn is_whole_range(&self) -> bool {
643         matches!(
644             *self,
645             AsBlock::Range(range)
646                 if range.min() == AsId::MIN && range.max() == AsId::MAX
647         )
648     }
649 }
650 
651 impl AsBlock {
652     /// Takes an optional AS bock from the beginning of an encoded value.
take_opt_from<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<Option<Self>, S::Err>653     pub fn take_opt_from<S: decode::Source>(
654         cons: &mut decode::Constructed<S>
655     ) -> Result<Option<Self>, S::Err> {
656         cons.take_opt_value(|tag, content| {
657             if tag == Tag::INTEGER {
658                 AsId::parse_content(content).map(AsBlock::Id)
659             }
660             else if tag == Tag::SEQUENCE {
661                 AsRange::parse_content(content).map(AsBlock::Range)
662             }
663             else {
664                 xerr!(Err(decode::Error::Malformed.into()))
665             }
666         })
667     }
668 
669     /// Skips over the AS block at the beginning of an encoded value.
skip_opt_in<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<Option<()>, S::Err>670     pub fn skip_opt_in<S: decode::Source>(
671         cons: &mut decode::Constructed<S>
672     ) -> Result<Option<()>, S::Err> {
673         cons.take_opt_value(|tag, content| {
674             if tag == Tag::INTEGER {
675                 AsId::skip_content(content)
676             }
677             else if tag == Tag::SEQUENCE {
678                 AsRange::skip_content(content)
679             }
680             else {
681                 xerr!(Err(decode::Error::Malformed.into()))
682             }
683         })
684     }
685 
encode(self) -> impl encode::Values686     fn encode(self) -> impl encode::Values {
687         match self {
688             AsBlock::Id(inner) => encode::Choice2::One(inner.encode()),
689             AsBlock::Range(inner) => encode::Choice2::Two(inner.encode()),
690         }
691     }
692 }
693 
694 
695 //--- From and FromStr
696 
697 impl From<AsId> for AsBlock {
from(id: AsId) -> Self698     fn from(id: AsId) -> Self {
699         AsBlock::Id(id)
700     }
701 }
702 
703 impl From<AsRange> for AsBlock {
from(range: AsRange) -> Self704     fn from(range: AsRange) -> Self {
705         AsBlock::Range(range)
706     }
707 }
708 
709 impl From<(AsId, AsId)> for AsBlock {
from(range: (AsId, AsId)) -> Self710     fn from(range: (AsId, AsId)) -> Self {
711         AsBlock::Range(AsRange::new(range.0, range.1))
712     }
713 }
714 
715 impl FromStr for AsBlock {
716     type Err = FromStrError;
717 
from_str(s: &str) -> Result<Self, Self::Err>718     fn from_str(s: &str) -> Result<Self, Self::Err> {
719 
720         match s.find('-') {
721             None => Ok(AsBlock::Id(AsId::from_str(s)?)),
722             Some(pos) => {
723                 if s.len() < pos + 2 {
724                     Err(FromStrError::BadRange)
725                 } else {
726                     let min_str = &s[..pos];
727                     let max_str = &s[pos + 1 ..];
728                     let min = AsId::from_str(min_str)
729                         .map_err(|_| FromStrError::BadRange)?;
730                     let max = AsId::from_str(max_str)
731                         .map_err(|_| FromStrError::BadRange)?;
732                     Ok(AsBlock::Range(AsRange { min, max }))
733                 }
734             }
735         }
736     }
737 }
738 
739 impl PartialEq for AsBlock {
eq(&self, other: &AsBlock) -> bool740     fn eq(&self, other: &AsBlock) -> bool {
741         self.is_equivalent(other)
742     }
743 }
744 
745 impl Eq for AsBlock {}
746 
747 
748 //--- Block
749 
750 impl Block for AsBlock {
751     type Item = AsId;
752 
new(min: Self::Item, max: Self::Item) -> Self753     fn new(min: Self::Item, max: Self::Item) -> Self {
754         if min == max {
755             AsBlock::Id(min)
756         }
757         else {
758             AsBlock::Range(AsRange::new(min, max))
759         }
760     }
761 
min(&self) -> Self::Item762     fn min(&self) -> Self::Item {
763         self.min()
764     }
765 
max(&self) -> Self::Item766     fn max(&self) -> Self::Item {
767         self.max()
768     }
769 
next(item: Self::Item) -> Option<Self::Item>770     fn next(item: Self::Item) -> Option<Self::Item> {
771         item.0.checked_add(1).map(AsId)
772     }
773 
previous(item: Self::Item) -> Option<Self::Item>774     fn previous(item: Self::Item) -> Option<Self::Item> {
775         item.0.checked_sub(1).map(AsId)
776     }
777 }
778 
779 //--- Display
780 
781 impl fmt::Display for AsBlock {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result782     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
783         match self {
784             AsBlock::Id(id) => id.fmt(f),
785             AsBlock::Range(range) => range.fmt(f)
786         }
787     }
788 }
789 
790 
791 //------------ AsRange -------------------------------------------------------
792 
793 /// A range of AS numbers.
794 #[derive(Clone, Copy, Debug)]
795 pub struct AsRange {
796     /// The smallest AS number that is part of the range.
797     min: AsId,
798 
799     /// The largest AS number that is part of the range.
800     ///
801     /// Note that this means that, unlike normal Rust ranges, our range is
802     /// inclusive at the upper end. This is necessary to represent a range
803     /// that goes all the way to the last number.
804     max: AsId,
805 }
806 
807 impl AsRange {
808     /// Creates a new AS number range from the smallest and largest number.
new(min: AsId, max: AsId) -> Self809     pub fn new(min: AsId, max: AsId) -> Self {
810         AsRange { min, max }
811     }
812 
813     /// Returns the smallest AS number that is part of this range.
min(self) -> AsId814     pub fn min(self) -> AsId {
815         self.min
816     }
817 
818     /// Returns the largest AS number that is still part of this range.
max(self) -> AsId819     pub fn max(self) -> AsId {
820         self.max
821     }
822 }
823 
824 impl AsRange {
825     /// Parses the content of an AS range value.
parse_content<S: decode::Source>( content: &mut decode::Content<S> ) -> Result<Self, S::Err>826     fn parse_content<S: decode::Source>(
827         content: &mut decode::Content<S>
828     ) -> Result<Self, S::Err> {
829         let cons = content.as_constructed()?;
830         Ok(AsRange {
831             min: AsId::take_from(cons)?,
832             max: AsId::take_from(cons)?,
833         })
834     }
835 
836     /// Skips over the content of an AS range value.
skip_content<S: decode::Source>( content: &mut decode::Content<S> ) -> Result<(), S::Err>837     fn skip_content<S: decode::Source>(
838         content: &mut decode::Content<S>
839     ) -> Result<(), S::Err> {
840         let cons = content.as_constructed()?;
841         AsId::skip_in(cons)?;
842         AsId::skip_in(cons)?;
843         Ok(())
844     }
845 
encode(self) -> impl encode::Values846     fn encode(self) -> impl encode::Values {
847         encode::sequence((
848             self.min.encode(),
849             self.max.encode(),
850         ))
851     }
852 }
853 
854 
855 //--- Block
856 
857 impl Block for AsRange {
858     type Item = AsId;
859 
new(min: Self::Item, max: Self::Item) -> Self860     fn new(min: Self::Item, max: Self::Item) -> Self {
861         Self::new(min, max)
862     }
863 
min(&self) -> Self::Item864     fn min(&self) -> Self::Item {
865         Self::min(*self)
866     }
867 
max(&self) -> Self::Item868     fn max(&self) -> Self::Item {
869         Self::max(*self)
870     }
871 
next(item: Self::Item) -> Option<Self::Item>872     fn next(item: Self::Item) -> Option<Self::Item> {
873         item.0.checked_add(1).map(AsId)
874     }
875 
previous(item: Self::Item) -> Option<Self::Item>876     fn previous(item: Self::Item) -> Option<Self::Item> {
877         item.0.checked_sub(1).map(AsId)
878     }
879 }
880 
881 //--- Display
882 
883 impl fmt::Display for AsRange {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result884     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
885         write!(f, "{}-{}", self.min, self.max)
886     }
887 }
888 
889 
890 //------------ AsId ----------------------------------------------------------
891 
892 /// An AS number.
893 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
894 pub struct AsId(u32);
895 
896 impl AsId {
897     pub const MIN: AsId = AsId(std::u32::MIN);
898     pub const MAX: AsId = AsId(std::u32::MAX);
899 
900     /// Takes an AS number from the beginning of an encoded value.
take_from<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<Self, S::Err>901     pub fn take_from<S: decode::Source>(
902         cons: &mut decode::Constructed<S>
903     ) -> Result<Self, S::Err> {
904         cons.take_u32().map(AsId)
905     }
906 
907     /// Skips over the AS number at the beginning of an encoded value.
skip_in<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<(), S::Err>908     fn skip_in<S: decode::Source>(
909         cons: &mut decode::Constructed<S>
910     ) -> Result<(), S::Err> {
911         cons.take_u32().map(|_| ())
912     }
913 
914     /// Parses the content of an AS number value.
parse_content<S: decode::Source>( content: &mut decode::Content<S> ) -> Result<Self, S::Err>915     fn parse_content<S: decode::Source>(
916         content: &mut decode::Content<S>
917     ) -> Result<Self, S::Err> {
918         content.to_u32().map(AsId)
919     }
920 
921     /// Skips the content of an AS number value.
skip_content<S: decode::Source>( content: &mut decode::Content<S> ) -> Result<(), S::Err>922     fn skip_content<S: decode::Source>(
923         content: &mut decode::Content<S>
924     ) -> Result<(), S::Err> {
925         content.to_u32().map(|_| ())
926     }
927 
encode(self) -> impl encode::Values928     pub fn encode(self) -> impl encode::Values {
929         self.0.encode()
930     }
931 }
932 
933 
934 //--- From
935 
936 impl From<u32> for AsId {
from(id: u32) -> Self937     fn from(id: u32) -> Self {
938         AsId(id)
939     }
940 }
941 
942 impl From<AsId> for u32 {
from(id: AsId) -> Self943     fn from(id: AsId) -> Self {
944         id.0
945     }
946 }
947 
948 
949 //--- FromStr
950 
951 impl FromStr for AsId {
952     type Err = FromStrError;
953 
from_str(s: &str) -> Result<Self, Self::Err>954     fn from_str(s: &str) -> Result<Self, Self::Err> {
955 
956         let s = if s.len() > 2 && s[..2].eq_ignore_ascii_case("as") {
957             &s[2..]
958         } else {
959             s
960         };
961 
962         let id = u32::from_str(s).map_err(|_| FromStrError::BadAsn)?;
963         Ok(AsId(id))
964     }
965 }
966 
967 
968 //--- Serialize and Deserialize
969 
970 #[cfg(feature = "serde")]
971 impl serde::Serialize for AsId {
serialize<S: serde::Serializer>( &self, serializer: S ) -> Result<S::Ok, S::Error>972     fn serialize<S: serde::Serializer>(
973         &self, serializer: S
974     ) -> Result<S::Ok, S::Error> {
975         let s = format!("{}", self);
976         serializer.serialize_str(&s)
977     }
978 }
979 
980 #[cfg(feature = "serde")]
981 impl<'de> serde::de::Deserialize<'de> for AsId {
deserialize<D: serde::de::Deserializer<'de>>( deserializer: D ) -> Result<Self, D::Error>982     fn deserialize<D: serde::de::Deserializer<'de>>(
983         deserializer: D
984     ) -> Result<Self, D::Error> {
985         struct Visitor;
986 
987         impl<'de> serde::de::Visitor<'de> for Visitor {
988             type Value = AsId;
989 
990             fn expecting(
991                 &self, formatter: &mut fmt::Formatter
992             ) -> fmt::Result {
993                 write!(formatter, "a string with an AS number")
994             }
995 
996             fn visit_str<E: serde::de::Error>(
997                 self, v: &str
998             ) -> Result<Self::Value, E> {
999                 AsId::from_str(v).map_err(E::custom)
1000             }
1001         }
1002 
1003         deserializer.deserialize_str(Visitor)
1004     }
1005 }
1006 
1007 
1008 //--- Add
1009 
1010 impl ops::Add<u32> for AsId {
1011     type Output = Self;
1012 
add(self, rhs: u32) -> Self1013     fn add(self, rhs: u32) -> Self {
1014         AsId(self.0.checked_add(rhs).unwrap())
1015     }
1016 }
1017 
1018 
1019 //--- Display
1020 
1021 impl fmt::Display for AsId {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1022     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1023         write!(f, "AS{}", self.0)
1024     }
1025 }
1026 
1027 
1028 //------------ FromStrError --------------------------------------------------
1029 
1030 #[derive(Clone, Debug, Eq, PartialEq)]
1031 #[allow(clippy::enum_variant_names)]
1032 pub enum FromStrError {
1033     BadAsn,
1034     BadRange,
1035     BadBlocks,
1036 }
1037 
1038 impl fmt::Display for FromStrError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1039     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1040         f.write_str(match *self {
1041             FromStrError::BadAsn
1042                 => "Bad AS number. Expected format: AS#",
1043             FromStrError::BadRange
1044                 => "Bad AS range. Expected format: AS#-AS#",
1045             FromStrError::BadBlocks
1046                 => "Cannot parse blocks."
1047         })
1048     }
1049 }
1050 
1051 impl error::Error for FromStrError { }
1052 
1053 
1054 //============ Tests =========================================================
1055 
1056 #[cfg(test)]
1057 mod test {
1058     use super::*;
1059     use serde_test::{Token, assert_de_tokens, assert_tokens};
1060 
1061     #[test]
as_id_from_str()1062     fn as_id_from_str() {
1063         assert_eq!(AsId::from_str("AS1").unwrap(), AsId(1));
1064         assert_eq!(AsId::from_str("As1").unwrap(), AsId(1));
1065         assert_eq!(AsId::from_str("1").unwrap(), AsId(1));
1066     }
1067 
1068     #[test]
as_id_display()1069     fn as_id_display() {
1070         assert_eq!(format!("{}", AsId(1)), "AS1");
1071     }
1072 
1073     #[test]
as_id_serde()1074     fn as_id_serde() {
1075         assert_tokens(&AsId(12), &[Token::Str("AS12")]);
1076         assert_de_tokens(&AsId(12), &[Token::Str("as12")]);
1077         assert_de_tokens(&AsId(12), &[Token::Str("12")]);
1078     }
1079 
1080     #[test]
as_block_from_str()1081     fn as_block_from_str() {
1082         // Good
1083         assert_eq!(
1084             AsBlock::from_str("AS1").unwrap(),
1085             AsId(1).into()
1086         );
1087         assert_eq!(
1088             AsBlock::from_str("AS1-AS3").unwrap(),
1089             AsRange::new(AsId(1), AsId(3)).into()
1090         );
1091 
1092         // Bad
1093         assert!(AsBlock::from_str("AS1-").is_err());
1094     }
1095 
1096     #[test]
as_blocks_from_str()1097     fn as_blocks_from_str() {
1098         fn good(left: &str, right: Vec<AsBlock>) {
1099             assert_eq!(
1100                 AsBlocks::from_str(left).unwrap().iter().collect::<Vec<_>>(),
1101                 right
1102             );
1103         }
1104 
1105         good(
1106             "AS1, AS3-AS7",
1107             vec![AsId(1).into(), AsRange::new(AsId(3), AsId(7)).into()]
1108         );
1109         good(
1110             "AS1,AS3-AS7",
1111             vec![AsId(1).into(), AsRange::new(AsId(3), AsId(7)).into()]
1112         );
1113         good("", Vec::new());
1114     }
1115 
1116     #[test]
as_blocks_difference()1117     fn as_blocks_difference() {
1118         // This delegates to Chain::difference which is well tested
1119         let left = "AS1, AS3-AS7";
1120         let right = "AS2, AS5-AS7";
1121         let expected = "AS1, AS3-AS4";
1122 
1123         let left = AsBlocks::from_str(left).unwrap();
1124         let right = AsBlocks::from_str(right).unwrap();
1125         let expected = AsBlocks::from_str(expected).unwrap();
1126 
1127         let found = left.difference(&right);
1128 
1129         assert_eq!(expected, found);
1130     }
1131 
1132 
1133     #[test]
1134     #[cfg(feature = "serde")]
as_resources_inherit_serde()1135     fn as_resources_inherit_serde() {
1136         let resources_str = "inherit";
1137         let as_resources = AsResources::from_str(resources_str).unwrap();
1138 
1139         let json = serde_json::to_string(&as_resources).unwrap();
1140         let deser_as_resources = serde_json::from_str(&json).unwrap();
1141 
1142         assert_eq!(as_resources, deser_as_resources)
1143     }
1144 
1145     #[test]
1146     #[cfg(feature = "serde")]
as_resources_concrete_serde()1147     fn as_resources_concrete_serde() {
1148         let resources_str = "AS6500-AS65005, AS65007";
1149         let as_resources = AsResources::from_str(resources_str).unwrap();
1150 
1151         let json = serde_json::to_string(&as_resources).unwrap();
1152         let deser_as_resources = serde_json::from_str(&json).unwrap();
1153 
1154         assert_eq!(as_resources, deser_as_resources)
1155     }
1156 }
1157