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