1use std::{
4 cmp::Ordering,
5 net::{AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr},
6 num::ParseIntError,
7};
8
9#[cfg(feature = "ula")]
10use {
11 rand::Rng,
12 std::time::{SystemTime, SystemTimeError},
13};
14
15#[derive(Debug, Clone, PartialEq)]
17pub struct IpNetPrefixError(u8);
18
19impl std::fmt::Display for IpNetPrefixError {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 write!(f, "invalid network prefix {}", self.0)
22 }
23}
24impl std::error::Error for IpNetPrefixError {}
25
26#[derive(Debug, Clone)]
28pub enum IpNetParseError {
29 InvalidAddr(AddrParseError),
31 PrefixValue(IpNetPrefixError),
33 NoPrefix,
35 InvalidPrefix(ParseIntError),
37}
38
39impl std::fmt::Display for IpNetParseError {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 match self {
42 IpNetParseError::InvalidAddr(e) => e.fmt(f),
43 IpNetParseError::PrefixValue(e) => {
44 write!(f, "invalid prefix value: {e}")
45 }
46 IpNetParseError::NoPrefix => write!(f, "missing '/' character"),
47 IpNetParseError::InvalidPrefix(e) => e.fmt(f),
48 }
49 }
50}
51impl std::error::Error for IpNetParseError {}
52
53#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
55#[cfg_attr(feature = "serde", serde(untagged))]
56#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
57pub enum IpNet {
58 V4(Ipv4Net),
60 V6(Ipv6Net),
62}
63
64impl IpNet {
65 pub fn new(addr: IpAddr, prefix: u8) -> Result<Self, IpNetPrefixError> {
67 match addr {
68 IpAddr::V4(addr) => Ok(Self::V4(Ipv4Net::new(addr, prefix)?)),
69 IpAddr::V6(addr) => Ok(Self::V6(Ipv6Net::new(addr, prefix)?)),
70 }
71 }
72
73 pub const fn new_unchecked(addr: IpAddr, prefix: u8) -> Self {
76 match addr {
77 IpAddr::V4(addr) => Self::V4(Ipv4Net::new_unchecked(addr, prefix)),
78 IpAddr::V6(addr) => Self::V6(Ipv6Net::new_unchecked(addr, prefix)),
79 }
80 }
81
82 pub fn host_net(addr: IpAddr) -> Self {
84 match addr {
85 IpAddr::V4(addr) => Self::V4(Ipv4Net::host_net(addr)),
86 IpAddr::V6(addr) => Self::V6(Ipv6Net::host_net(addr)),
87 }
88 }
89
90 pub const fn addr(&self) -> IpAddr {
92 match self {
93 IpNet::V4(inner) => IpAddr::V4(inner.addr()),
94 IpNet::V6(inner) => IpAddr::V6(inner.addr()),
95 }
96 }
97
98 pub fn prefix(&self) -> IpAddr {
100 match self {
101 IpNet::V4(inner) => inner.prefix().into(),
102 IpNet::V6(inner) => inner.prefix().into(),
103 }
104 }
105
106 pub const fn width(&self) -> u8 {
108 match self {
109 IpNet::V4(inner) => inner.width(),
110 IpNet::V6(inner) => inner.width(),
111 }
112 }
113
114 pub fn mask_addr(&self) -> IpAddr {
116 match self {
117 IpNet::V4(inner) => inner.mask_addr().into(),
118 IpNet::V6(inner) => inner.mask_addr().into(),
119 }
120 }
121
122 pub const fn is_host_net(&self) -> bool {
125 match self {
126 IpNet::V4(inner) => inner.is_host_net(),
127 IpNet::V6(inner) => inner.is_host_net(),
128 }
129 }
130
131 pub fn is_network_address(&self) -> bool {
134 match self {
135 IpNet::V4(inner) => inner.is_network_address(),
136 IpNet::V6(inner) => inner.is_network_address(),
137 }
138 }
139
140 pub const fn is_multicast(&self) -> bool {
142 match self {
143 IpNet::V4(inner) => inner.is_multicast(),
144 IpNet::V6(inner) => inner.is_multicast(),
145 }
146 }
147
148 pub const fn is_admin_scoped_multicast(&self) -> bool {
165 match self {
166 IpNet::V4(inner) => inner.is_admin_scoped_multicast(),
167 IpNet::V6(inner) => inner.is_admin_scoped_multicast(),
168 }
169 }
170
171 pub const fn is_admin_local_multicast(&self) -> bool {
179 match self {
180 IpNet::V4(_inner) => false,
181 IpNet::V6(inner) => inner.is_admin_local_multicast(),
182 }
183 }
184
185 pub const fn is_local_multicast(&self) -> bool {
191 match self {
192 IpNet::V4(inner) => inner.is_local_multicast(),
193 IpNet::V6(_inner) => false,
194 }
195 }
196
197 pub const fn is_site_local_multicast(&self) -> bool {
204 match self {
205 IpNet::V4(_inner) => false,
206 IpNet::V6(inner) => inner.is_site_local_multicast(),
207 }
208 }
209
210 pub const fn is_org_local_multicast(&self) -> bool {
220 match self {
221 IpNet::V4(inner) => inner.is_org_local_multicast(),
222 IpNet::V6(inner) => inner.is_org_local_multicast(),
223 }
224 }
225
226 pub const fn is_unique_local(&self) -> bool {
229 match self {
230 IpNet::V4(_inner) => false, IpNet::V6(inner) => inner.is_unique_local(),
232 }
233 }
234
235 pub const fn is_loopback(&self) -> bool {
237 match self {
238 IpNet::V4(inner) => inner.is_loopback(),
239 IpNet::V6(inner) => inner.is_loopback(),
240 }
241 }
242
243 pub fn contains(&self, addr: IpAddr) -> bool {
248 match (self, addr) {
249 (IpNet::V4(net), IpAddr::V4(ip)) => net.contains(ip),
250 (IpNet::V6(net), IpAddr::V6(ip)) => net.contains(ip),
251 (_, _) => false,
252 }
253 }
254
255 pub fn is_subnet_of(&self, other: &Self) -> bool {
260 match (self, other) {
261 (IpNet::V4(net), IpNet::V4(other)) => net.is_subnet_of(other),
262 (IpNet::V6(net), IpNet::V6(other)) => net.is_subnet_of(other),
263 (_, _) => false,
264 }
265 }
266
267 pub fn is_supernet_of(&self, other: &Self) -> bool {
272 other.is_subnet_of(self)
273 }
274
275 pub fn overlaps(&self, other: &Self) -> bool {
280 match (self, other) {
281 (IpNet::V4(net), IpNet::V4(other)) => net.overlaps(other),
282 (IpNet::V6(net), IpNet::V6(other)) => net.overlaps(other),
283 (_, _) => false,
284 }
285 }
286
287 pub const fn is_ipv4(&self) -> bool {
289 matches!(self, IpNet::V4(_))
290 }
291
292 pub const fn is_ipv6(&self) -> bool {
294 matches!(self, IpNet::V6(_))
295 }
296}
297
298impl From<Ipv4Net> for IpNet {
299 fn from(n: Ipv4Net) -> IpNet {
300 IpNet::V4(n)
301 }
302}
303
304impl From<Ipv6Net> for IpNet {
305 fn from(n: Ipv6Net) -> IpNet {
306 IpNet::V6(n)
307 }
308}
309
310impl std::fmt::Display for IpNet {
311 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312 match self {
313 IpNet::V4(inner) => write!(f, "{inner}"),
314 IpNet::V6(inner) => write!(f, "{inner}"),
315 }
316 }
317}
318
319impl std::str::FromStr for IpNet {
320 type Err = IpNetParseError;
321
322 fn from_str(s: &str) -> Result<Self, Self::Err> {
323 let Some((addr_str, prefix_str)) = s.split_once('/') else {
324 return Err(IpNetParseError::NoPrefix);
325 };
326
327 let prefix = prefix_str.parse().map_err(IpNetParseError::InvalidPrefix)?;
328 let addr = addr_str.parse().map_err(IpNetParseError::InvalidAddr)?;
329 IpNet::new(addr, prefix).map_err(IpNetParseError::PrefixValue)
330 }
331}
332
333#[cfg(feature = "schemars")]
334impl schemars::JsonSchema for IpNet {
335 fn schema_name() -> String {
336 "IpNet".to_string()
337 }
338
339 fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
340 use crate::schema_util::label_schema;
341 schemars::schema::SchemaObject {
342 subschemas: Some(Box::new(schemars::schema::SubschemaValidation {
343 one_of: Some(vec![
344 label_schema("v4", gen.subschema_for::<Ipv4Net>()),
345 label_schema("v6", gen.subschema_for::<Ipv6Net>()),
346 ]),
347 ..Default::default()
348 })),
349 extensions: crate::schema_util::extension("IpNet", "0.1.0"),
350 ..Default::default()
351 }
352 .into()
353 }
354}
355
356pub const IPV4_NET_WIDTH_MAX: u8 = 32;
358
359#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
361pub struct Ipv4Net {
362 addr: Ipv4Addr,
363 width: u8,
364}
365
366impl Ipv4Net {
367 pub fn new(addr: Ipv4Addr, width: u8) -> Result<Self, IpNetPrefixError> {
369 if width > IPV4_NET_WIDTH_MAX {
370 Err(IpNetPrefixError(width))
371 } else {
372 Ok(Self { addr, width })
373 }
374 }
375
376 pub const fn new_unchecked(addr: Ipv4Addr, width: u8) -> Self {
379 Self { addr, width }
380 }
381
382 pub const fn host_net(addr: Ipv4Addr) -> Self {
384 Self {
385 addr,
386 width: IPV4_NET_WIDTH_MAX,
387 }
388 }
389
390 pub const fn addr(&self) -> Ipv4Addr {
392 self.addr
393 }
394
395 pub const fn width(&self) -> u8 {
397 self.width
398 }
399
400 pub(crate) fn mask(&self) -> u32 {
401 Self::mask_for_width(self.width)
402 }
403
404 pub(crate) fn mask_for_width(width: u8) -> u32 {
405 u32::MAX
406 .checked_shl((IPV4_NET_WIDTH_MAX - width) as u32)
407 .unwrap_or(0)
408 }
409
410 pub fn mask_addr(&self) -> Ipv4Addr {
412 Ipv4Addr::from(self.mask())
413 }
414
415 pub const fn is_host_net(&self) -> bool {
418 self.width == IPV4_NET_WIDTH_MAX
419 }
420
421 pub fn is_network_address(&self) -> bool {
424 self.addr == self.prefix()
425 }
426
427 pub const fn is_multicast(&self) -> bool {
429 self.addr.is_multicast()
430 }
431
432 pub const fn is_admin_scoped_multicast(&self) -> bool {
441 self.addr.octets()[0] == 239
445 }
446
447 pub const fn is_local_multicast(&self) -> bool {
453 let octets = self.addr.octets();
455 octets[0] == 239 && octets[1] == 255
456 }
457
458 pub const fn is_org_local_multicast(&self) -> bool {
463 let octets = self.addr.octets();
466 octets[0] == 239 && (octets[1] >= 192 && octets[1] <= 195)
467 }
468
469 pub const fn is_loopback(&self) -> bool {
471 self.addr.is_loopback()
472 }
473
474 pub const fn size(&self) -> Option<u32> {
478 1u32.checked_shl((IPV4_NET_WIDTH_MAX - self.width) as u32)
479 }
480
481 pub fn prefix(&self) -> Ipv4Addr {
483 self.first_addr()
484 }
485
486 pub fn network(&self) -> Option<Ipv4Addr> {
489 (self.width < 31).then(|| self.first_addr())
490 }
491
492 pub fn broadcast(&self) -> Option<Ipv4Addr> {
495 (self.width < 31).then(|| self.last_addr())
496 }
497
498 pub fn first_addr(&self) -> Ipv4Addr {
500 let addr: u32 = self.addr.into();
501 Ipv4Addr::from(addr & self.mask())
502 }
503
504 pub fn last_addr(&self) -> Ipv4Addr {
506 let addr: u32 = self.addr.into();
507 Ipv4Addr::from(addr | !self.mask())
508 }
509
510 pub fn first_host(&self) -> Ipv4Addr {
514 let mask = self.mask();
515 let addr: u32 = self.addr.into();
516 let first = addr & mask;
517 if self.width == 31 || self.width == 32 {
518 Ipv4Addr::from(first)
519 } else {
520 Ipv4Addr::from(first + 1)
521 }
522 }
523
524 pub fn last_host(&self) -> Ipv4Addr {
529 let mask = self.mask();
530 let addr: u32 = self.addr.into();
531 let last = addr | !mask;
532 if self.width == 31 || self.width == 32 {
533 Ipv4Addr::from(last)
534 } else {
535 Ipv4Addr::from(last - 1)
536 }
537 }
538
539 pub fn contains(&self, other: Ipv4Addr) -> bool {
541 let mask = self.mask();
542 let addr: u32 = self.addr.into();
543 let other: u32 = other.into();
544
545 (addr & mask) == (other & mask)
546 }
547
548 pub fn nth(&self, n: usize) -> Option<Ipv4Addr> {
551 let addr: u32 = self.addr.into();
552 let nth = addr.checked_add(n.try_into().ok()?)?;
553 (nth <= self.last_addr().into()).then_some(nth.into())
554 }
555
556 pub fn addr_iter(&self) -> impl Iterator<Item = Ipv4Addr> {
558 Ipv4NetIter {
559 next: Some(self.first_addr().into()),
560 last: self.last_addr().into(),
561 }
562 }
563
564 pub fn host_iter(&self) -> impl Iterator<Item = Ipv4Addr> {
568 Ipv4NetIter {
569 next: Some(self.first_host().into()),
570 last: self.last_host().into(),
571 }
572 }
573
574 pub fn is_subnet_of(&self, other: &Self) -> bool {
576 other.first_addr() <= self.first_addr() && other.last_addr() >= self.last_addr()
577 }
578
579 pub fn is_supernet_of(&self, other: &Self) -> bool {
581 other.is_subnet_of(self)
582 }
583
584 pub fn overlaps(&self, other: &Self) -> bool {
587 let (parent, child) = if self.width <= other.width {
588 (self, other)
589 } else {
590 (other, self)
591 };
592
593 child.is_subnet_of(parent)
594 }
595
596 pub fn resize(&self, width: u8, fill: u32) -> Result<Self, IpNetPrefixError> {
630 if width > IPV4_NET_WIDTH_MAX {
631 return Err(IpNetPrefixError(width));
632 }
633 match width.cmp(&self.width) {
634 Ordering::Less => Ok(Self {
635 addr: Ipv4Addr::from(u32::from(self.addr) & Self::mask_for_width(width)),
636 width,
637 }),
638 Ordering::Equal => Ok(*self),
639 Ordering::Greater => {
640 let fill = (fill << (IPV4_NET_WIDTH_MAX - width)) & Self::mask_for_width(width);
641 Ok(Self {
642 addr: Ipv4Addr::from(u32::from(self.addr) | fill),
643 width,
644 })
645 }
646 }
647 }
648}
649
650impl std::fmt::Display for Ipv4Net {
651 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
652 write!(f, "{}/{}", &self.addr, self.width)
653 }
654}
655
656impl std::str::FromStr for Ipv4Net {
657 type Err = IpNetParseError;
658
659 fn from_str(s: &str) -> Result<Self, Self::Err> {
660 let Some((addr_str, prefix_str)) = s.split_once('/') else {
661 return Err(IpNetParseError::NoPrefix);
662 };
663
664 let prefix = prefix_str.parse().map_err(IpNetParseError::InvalidPrefix)?;
665 let addr = addr_str.parse().map_err(IpNetParseError::InvalidAddr)?;
666 Ipv4Net::new(addr, prefix).map_err(IpNetParseError::PrefixValue)
667 }
668}
669
670#[cfg(feature = "serde")]
671impl<'de> serde::Deserialize<'de> for Ipv4Net {
672 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
673 where
674 D: serde::Deserializer<'de>,
675 {
676 String::deserialize(deserializer)?
677 .parse()
678 .map_err(<D::Error as serde::de::Error>::custom)
679 }
680}
681
682#[cfg(feature = "serde")]
683impl serde::Serialize for Ipv4Net {
684 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
685 where
686 S: serde::Serializer,
687 {
688 serializer.serialize_str(&format!("{self}"))
689 }
690}
691
692#[cfg(feature = "schemars")]
693const IPV4_NET_REGEX: &str = concat!(
694 r#"^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}"#,
695 r#"([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"#,
696 r#"/([0-9]|1[0-9]|2[0-9]|3[0-2])$"#,
697);
698
699#[cfg(feature = "schemars")]
700impl schemars::JsonSchema for Ipv4Net {
701 fn schema_name() -> String {
702 "Ipv4Net".to_string()
703 }
704
705 fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
706 schemars::schema::SchemaObject {
707 metadata: Some(Box::new(schemars::schema::Metadata {
708 title: Some("An IPv4 subnet".to_string()),
709 description: Some("An IPv4 subnet, including prefix and prefix length".to_string()),
710 examples: vec!["192.168.1.0/24".into()],
711 ..Default::default()
712 })),
713 instance_type: Some(schemars::schema::InstanceType::String.into()),
714 string: Some(Box::new(schemars::schema::StringValidation {
715 pattern: Some(IPV4_NET_REGEX.to_string()),
716 ..Default::default()
717 })),
718 extensions: crate::schema_util::extension("Ipv4Net", "0.1.0"),
719 ..Default::default()
720 }
721 .into()
722 }
723}
724
725pub const IPV6_NET_WIDTH_MAX: u8 = 128;
727
728#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
733#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
734pub enum MulticastScopeV6 {
735 InterfaceLocal = 0x1,
737 LinkLocal = 0x2,
739 AdminLocal = 0x4,
741 SiteLocal = 0x5,
743 OrganizationLocal = 0x8,
745 Global = 0xE,
747}
748
749impl MulticastScopeV6 {
750 pub const fn is_admin_scoped_multicast(&self) -> bool {
753 matches!(
754 self,
755 MulticastScopeV6::AdminLocal
756 | MulticastScopeV6::SiteLocal
757 | MulticastScopeV6::OrganizationLocal
758 )
759 }
760
761 pub const fn from_u8(scope: u8) -> Option<Self> {
764 match scope {
765 0x1 => Some(MulticastScopeV6::InterfaceLocal),
766 0x2 => Some(MulticastScopeV6::LinkLocal),
767 0x4 => Some(MulticastScopeV6::AdminLocal),
768 0x5 => Some(MulticastScopeV6::SiteLocal),
769 0x8 => Some(MulticastScopeV6::OrganizationLocal),
770 0xE => Some(MulticastScopeV6::Global),
771 _ => None,
772 }
773 }
774}
775
776#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
778pub struct Ipv6Net {
779 addr: Ipv6Addr,
780 width: u8,
781}
782
783impl Ipv6Net {
784 pub fn new(addr: Ipv6Addr, width: u8) -> Result<Self, IpNetPrefixError> {
786 if width > IPV6_NET_WIDTH_MAX {
787 Err(IpNetPrefixError(width))
788 } else {
789 Ok(Self { addr, width })
790 }
791 }
792
793 pub const fn new_unchecked(addr: Ipv6Addr, width: u8) -> Self {
796 Self { addr, width }
797 }
798
799 pub const fn host_net(addr: Ipv6Addr) -> Self {
801 Self {
802 addr,
803 width: IPV6_NET_WIDTH_MAX,
804 }
805 }
806
807 pub const fn addr(&self) -> Ipv6Addr {
809 self.addr
810 }
811
812 pub const fn width(&self) -> u8 {
814 self.width
815 }
816
817 pub(crate) fn mask(&self) -> u128 {
818 Self::mask_for_width(self.width)
819 }
820
821 pub(crate) fn mask_for_width(width: u8) -> u128 {
822 u128::MAX
823 .checked_shl((IPV6_NET_WIDTH_MAX - width) as u32)
824 .unwrap_or(0)
825 }
826
827 pub fn mask_addr(&self) -> Ipv6Addr {
829 Ipv6Addr::from(self.mask())
830 }
831
832 pub const fn is_host_net(&self) -> bool {
835 self.width == IPV6_NET_WIDTH_MAX
836 }
837
838 pub fn is_network_address(&self) -> bool {
841 self.addr == self.prefix()
842 }
843
844 pub const fn is_multicast(&self) -> bool {
846 self.addr.is_multicast()
847 }
848
849 pub const fn multicast_scope(&self) -> Option<MulticastScopeV6> {
856 if !self.addr.is_multicast() {
857 return None;
858 }
859
860 let segments = self.addr.segments();
862 let scope = (segments[0] & 0x000F) as u8;
863
864 MulticastScopeV6::from_u8(scope)
865 }
866
867 pub const fn is_admin_scoped_multicast(&self) -> bool {
881 match self.multicast_scope() {
882 Some(scope) => scope.is_admin_scoped_multicast(),
883 None => false,
884 }
885 }
886
887 pub const fn is_admin_local_multicast(&self) -> bool {
893 matches!(self.multicast_scope(), Some(MulticastScopeV6::AdminLocal))
894 }
895
896 pub const fn is_site_local_multicast(&self) -> bool {
902 matches!(self.multicast_scope(), Some(MulticastScopeV6::SiteLocal))
903 }
904
905 pub const fn is_org_local_multicast(&self) -> bool {
911 matches!(
912 self.multicast_scope(),
913 Some(MulticastScopeV6::OrganizationLocal)
914 )
915 }
916
917 pub const fn is_loopback(&self) -> bool {
919 self.addr.is_loopback()
920 }
921
922 pub const fn size(&self) -> Option<u128> {
926 1u128.checked_shl((IPV6_NET_WIDTH_MAX - self.width) as u32)
927 }
928
929 pub fn prefix(&self) -> Ipv6Addr {
931 self.first_addr()
932 }
933
934 pub const fn is_unique_local(&self) -> bool {
939 self.addr.is_unique_local()
940 }
941
942 pub fn first_addr(&self) -> Ipv6Addr {
944 let addr: u128 = self.addr.into();
945 Ipv6Addr::from(addr & self.mask())
946 }
947
948 pub fn last_addr(&self) -> Ipv6Addr {
950 let addr: u128 = self.addr.into();
951 Ipv6Addr::from(addr | !self.mask())
952 }
953
954 pub fn iter(&self) -> impl Iterator<Item = Ipv6Addr> {
956 Ipv6NetIter {
957 next: Some(self.first_addr().into()),
958 last: self.last_addr().into(),
959 }
960 }
961
962 pub fn contains(&self, other: Ipv6Addr) -> bool {
964 let mask = self.mask();
965 let addr: u128 = self.addr.into();
966 let other: u128 = other.into();
967
968 (addr & mask) == (other & mask)
969 }
970
971 pub fn nth(&self, n: u128) -> Option<Ipv6Addr> {
974 let addr: u128 = self.addr.into();
975 let nth = addr.checked_add(n)?;
976 (nth <= self.last_addr().into()).then_some(nth.into())
977 }
978
979 pub fn is_subnet_of(&self, other: &Self) -> bool {
981 other.first_addr() <= self.first_addr() && other.last_addr() >= self.last_addr()
982 }
983
984 pub fn is_supernet_of(&self, other: &Self) -> bool {
986 other.is_subnet_of(self)
987 }
988
989 pub fn overlaps(&self, other: &Self) -> bool {
992 let (parent, child) = if self.width <= other.width {
993 (self, other)
994 } else {
995 (other, self)
996 };
997
998 child.is_subnet_of(parent)
999 }
1000
1001 pub fn resize(&self, width: u8, fill: u128) -> Result<Self, IpNetPrefixError> {
1034 if width > IPV6_NET_WIDTH_MAX {
1035 return Err(IpNetPrefixError(width));
1036 }
1037 match width.cmp(&self.width) {
1038 Ordering::Less => Ok(Self {
1039 addr: Ipv6Addr::from(u128::from(self.addr) & Self::mask_for_width(width)),
1040 width,
1041 }),
1042 Ordering::Equal => Ok(*self),
1043 Ordering::Greater => {
1044 let fill = (fill << (IPV6_NET_WIDTH_MAX - width)) & Self::mask_for_width(width);
1045 Ok(Self {
1046 addr: Ipv6Addr::from(u128::from(self.addr) | fill),
1047 width,
1048 })
1049 }
1050 }
1051 }
1052}
1053
1054impl std::fmt::Display for Ipv6Net {
1055 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1056 write!(f, "{}/{}", &self.addr, self.width)
1057 }
1058}
1059
1060impl std::str::FromStr for Ipv6Net {
1061 type Err = IpNetParseError;
1062
1063 fn from_str(s: &str) -> Result<Self, Self::Err> {
1064 let Some((addr_str, prefix_str)) = s.split_once('/') else {
1065 return Err(IpNetParseError::NoPrefix);
1066 };
1067
1068 let prefix = prefix_str.parse().map_err(IpNetParseError::InvalidPrefix)?;
1069 let addr = addr_str.parse().map_err(IpNetParseError::InvalidAddr)?;
1070 Ipv6Net::new(addr, prefix).map_err(IpNetParseError::PrefixValue)
1071 }
1072}
1073
1074#[cfg(feature = "serde")]
1075impl<'de> serde::Deserialize<'de> for Ipv6Net {
1076 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1077 where
1078 D: serde::Deserializer<'de>,
1079 {
1080 String::deserialize(deserializer)?
1081 .parse()
1082 .map_err(<D::Error as serde::de::Error>::custom)
1083 }
1084}
1085
1086#[cfg(feature = "serde")]
1087impl serde::Serialize for Ipv6Net {
1088 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1089 where
1090 S: serde::Serializer,
1091 {
1092 serializer.serialize_str(&format!("{self}"))
1093 }
1094}
1095
1096#[cfg(feature = "schemars")]
1097const IPV6_NET_REGEX: &str = concat!(
1098 r#"^("#,
1099 r#"([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|"#,
1100 r#"([0-9a-fA-F]{1,4}:){1,7}:|"#,
1101 r#"([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|"#,
1102 r#"([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|"#,
1103 r#"([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|"#,
1104 r#"([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|"#,
1105 r#"([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|"#,
1106 r#"[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|"#,
1107 r#":((:[0-9a-fA-F]{1,4}){1,7}|:)|"#,
1108 r#"fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|"#,
1109 r#"::(ffff(:0{1,4}){0,1}:){0,1}"#,
1110 r#"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}"#,
1111 r#"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|"#,
1112 r#"([0-9a-fA-F]{1,4}:){1,4}:"#,
1113 r#"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}"#,
1114 r#"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"#,
1115 r#")\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$"#,
1116);
1117
1118#[cfg(feature = "schemars")]
1119impl schemars::JsonSchema for Ipv6Net {
1120 fn schema_name() -> String {
1121 "Ipv6Net".to_string()
1122 }
1123
1124 fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
1125 schemars::schema::SchemaObject {
1126 metadata: Some(Box::new(schemars::schema::Metadata {
1127 title: Some("An IPv6 subnet".to_string()),
1128 description: Some("An IPv6 subnet, including prefix and subnet mask".to_string()),
1129 examples: vec!["fd12:3456::/64".into()],
1130 ..Default::default()
1131 })),
1132 instance_type: Some(schemars::schema::InstanceType::String.into()),
1133 string: Some(Box::new(schemars::schema::StringValidation {
1134 pattern: Some(IPV6_NET_REGEX.to_string()),
1135 ..Default::default()
1136 })),
1137 extensions: crate::schema_util::extension("Ipv6Net", "0.1.0"),
1138 ..Default::default()
1139 }
1140 .into()
1141 }
1142}
1143
1144pub struct Ipv4NetIter {
1145 next: Option<u32>,
1146 last: u32,
1147}
1148
1149impl Iterator for Ipv4NetIter {
1150 type Item = Ipv4Addr;
1151
1152 fn next(&mut self) -> Option<Self::Item> {
1153 let next = self.next?;
1154 if next == self.last {
1155 self.next = None;
1156 } else {
1157 self.next = Some(next + 1)
1158 }
1159 Some(next.into())
1160 }
1161
1162 fn nth(&mut self, n: usize) -> Option<Self::Item> {
1163 let next = self.next?;
1164 let nth = next.checked_add(n as u32)?;
1165 self.next = (nth <= self.last).then_some(nth);
1166 self.next()
1167 }
1168}
1169
1170pub struct Ipv6NetIter {
1171 next: Option<u128>,
1172 last: u128,
1173}
1174
1175impl Iterator for Ipv6NetIter {
1176 type Item = Ipv6Addr;
1177
1178 fn next(&mut self) -> Option<Self::Item> {
1179 let next = self.next?;
1180 if next == self.last {
1181 self.next = None;
1182 } else {
1183 self.next = Some(next + 1)
1184 }
1185 Some(next.into())
1186 }
1187
1188 fn nth(&mut self, n: usize) -> Option<Self::Item> {
1189 let next = self.next?;
1190 let nth = next.checked_add(n as u128)?;
1191 self.next = (nth <= self.last).then_some(nth);
1192 self.next()
1193 }
1194}
1195
1196#[cfg(feature = "ula")]
1198#[derive(Debug, Clone)]
1199pub enum UlaBuildError {
1200 Time(SystemTimeError),
1202 Prefix(IpNetPrefixError),
1204}
1205
1206#[cfg(feature = "ula")]
1207impl std::fmt::Display for UlaBuildError {
1208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1209 match self {
1210 Self::Time(e) => write!(f, "invalid time provided: {e}"),
1211 Self::Prefix(e) => write!(f, "unable to construct ULA prefix: {e}"),
1212 }
1213 }
1214}
1215
1216#[cfg(feature = "ula")]
1217impl std::error::Error for UlaBuildError {}
1218
1219#[cfg(feature = "ula")]
1220impl From<SystemTimeError> for UlaBuildError {
1221 fn from(value: SystemTimeError) -> Self {
1222 Self::Time(value)
1223 }
1224}
1225
1226#[cfg(feature = "ula")]
1227impl From<IpNetPrefixError> for UlaBuildError {
1228 fn from(value: IpNetPrefixError) -> Self {
1229 Self::Prefix(value)
1230 }
1231}
1232
1233#[cfg(feature = "ula")]
1235#[derive(Default)]
1236pub struct UlaBuilder {
1237 date: Option<SystemTime>,
1238 id: Option<Vec<u8>>,
1239}
1240
1241#[cfg(feature = "ula")]
1242impl UlaBuilder {
1243 pub fn id(&mut self, id: impl AsRef<[u8]>) -> &mut Self {
1245 self.id = Some(id.as_ref().to_vec());
1246 self
1247 }
1248
1249 pub fn date(&mut self, date: SystemTime) -> &mut Self {
1251 self.date = Some(date);
1252 self
1253 }
1254
1255 pub fn build(&self) -> Result<Ipv6Net, UlaBuildError> {
1262 use sha1::{Digest, Sha1};
1263 use std::time::SystemTime;
1264
1265 let id: Vec<u8> = self.id.clone().unwrap_or_else(|| {
1267 let mut rng = rand::rng();
1268 rng.random::<[u8; 8]>().to_vec()
1269 });
1270
1271 let time = self.date.unwrap_or_else(SystemTime::now);
1273 let ntp_time = system_time_to_ntp(time)?;
1274
1275 let mut hasher = Sha1::new();
1277 hasher.update(ntp_time.to_be_bytes());
1278 hasher.update(&id);
1279 let hash = hasher.finalize();
1280
1281 let global_id = &hash[..5];
1283
1284 let addr = Ipv6Addr::new(
1287 0xfd00 | (global_id[0] as u16),
1288 u16::from_be_bytes([global_id[1], global_id[2]]),
1289 u16::from_be_bytes([global_id[3], global_id[4]]),
1290 0,
1291 0,
1292 0,
1293 0,
1294 0,
1295 );
1296
1297 Ok(Ipv6Net::new(addr, 48)?)
1298 }
1299}
1300
1301#[cfg(feature = "ula")]
1302fn system_time_to_ntp(time: SystemTime) -> Result<u64, SystemTimeError> {
1303 use std::time::UNIX_EPOCH;
1304
1305 const NTP_UNIX_OFFSET: u64 = 2208988800;
1309
1310 let duration = time.duration_since(UNIX_EPOCH)?;
1311 let secs = duration.as_secs() + NTP_UNIX_OFFSET;
1312 let frac = ((duration.subsec_nanos() as u64) << 32) / 1_000_000_000;
1313
1314 Ok((secs << 32) | frac)
1315}
1316
1317#[cfg(feature = "ipnetwork")]
1318mod ipnetwork_feature {
1319 use super::*;
1320 use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network};
1321
1322 impl From<IpNetwork> for IpNet {
1323 fn from(value: IpNetwork) -> Self {
1324 match value {
1325 IpNetwork::V4(net) => Self::V4(net.into()),
1326 IpNetwork::V6(net) => Self::V6(net.into()),
1327 }
1328 }
1329 }
1330
1331 impl From<IpNet> for IpNetwork {
1332 fn from(value: IpNet) -> Self {
1333 match value {
1334 IpNet::V4(net) => Self::V4(net.into()),
1335 IpNet::V6(net) => Self::V6(net.into()),
1336 }
1337 }
1338 }
1339
1340 impl From<Ipv4Network> for Ipv4Net {
1341 fn from(value: Ipv4Network) -> Self {
1342 Self {
1343 addr: value.ip(),
1344 width: value.prefix(),
1345 }
1346 }
1347 }
1348
1349 impl From<Ipv4Net> for Ipv4Network {
1350 fn from(value: Ipv4Net) -> Self {
1351 Self::new(value.addr, value.width).unwrap()
1352 }
1353 }
1354
1355 impl From<Ipv6Network> for Ipv6Net {
1356 fn from(value: Ipv6Network) -> Self {
1357 Self {
1358 addr: value.ip(),
1359 width: value.prefix(),
1360 }
1361 }
1362 }
1363
1364 impl From<Ipv6Net> for Ipv6Network {
1365 fn from(value: Ipv6Net) -> Self {
1366 Self::new(value.addr, value.width).unwrap()
1367 }
1368 }
1369}
1370
1371#[cfg(test)]
1372mod tests {
1373 use super::*;
1374
1375 #[cfg(feature = "schemars")]
1376 #[test]
1377 fn test_ipv6_regex() {
1378 let re = regress::Regex::new(IPV6_NET_REGEX).unwrap();
1379 for case in [
1380 "1:2:3:4:5:6:7:8",
1381 "1:a:2:b:3:c:4:d",
1382 "1::",
1383 "::1",
1384 "::",
1385 "1::3:4:5:6:7:8",
1386 "1:2::4:5:6:7:8",
1387 "1:2:3::5:6:7:8",
1388 "1:2:3:4::6:7:8",
1389 "1:2:3:4:5::7:8",
1390 "1:2:3:4:5:6::8",
1391 "1:2:3:4:5:6:7::",
1392 "2001::",
1393 "fd00::",
1394 "::100:1",
1395 "fd12:3456::",
1396 ] {
1397 for prefix in 0..=128 {
1398 let net = format!("{case}/{prefix}");
1399 assert!(
1400 re.find(&net).is_some(),
1401 "Expected to match IPv6 case: {prefix}",
1402 );
1403 }
1404 }
1405 }
1406
1407 #[test]
1408 fn test_ipv4_net_operations() {
1409 let x: IpNet = "0.0.0.0/0".parse().unwrap();
1410 assert_eq!(x, IpNet::V4("0.0.0.0/0".parse().unwrap()));
1411 }
1412
1413 #[cfg(all(feature = "schemars", feature = "serde"))]
1414 #[test]
1415 fn test_ipnet_serde() {
1416 let net_str = "fd00:2::/32";
1417 let net: IpNet = net_str.parse().unwrap();
1418 let ser = serde_json::to_string(&net).unwrap();
1419
1420 assert_eq!(format!(r#""{net_str}""#), ser);
1421 let net_des = serde_json::from_str::<IpNet>(&ser).unwrap();
1422 assert_eq!(net, net_des);
1423
1424 let net_str = "fd00:47::1/64";
1425 let net: IpNet = net_str.parse().unwrap();
1426 let ser = serde_json::to_string(&net).unwrap();
1427
1428 assert_eq!(format!(r#""{net_str}""#), ser);
1429 let net_des = serde_json::from_str::<IpNet>(&ser).unwrap();
1430 assert_eq!(net, net_des);
1431
1432 let net_str = "192.168.1.1/16";
1433 let net: IpNet = net_str.parse().unwrap();
1434 let ser = serde_json::to_string(&net).unwrap();
1435
1436 assert_eq!(format!(r#""{net_str}""#), ser);
1437 let net_des = serde_json::from_str::<IpNet>(&ser).unwrap();
1438 assert_eq!(net, net_des);
1439
1440 let net_str = "0.0.0.0/0";
1441 let net: IpNet = net_str.parse().unwrap();
1442 let ser = serde_json::to_string(&net).unwrap();
1443
1444 assert_eq!(format!(r#""{net_str}""#), ser);
1445 let net_des = serde_json::from_str::<IpNet>(&ser).unwrap();
1446 assert_eq!(net, net_des);
1447 }
1448
1449 #[test]
1450 fn test_ipnet_size() {
1451 let net = Ipv4Net::host_net("1.2.3.4".parse().unwrap());
1452 assert_eq!(net.size(), Some(1));
1453 assert_eq!(net.width(), 32);
1454 assert_eq!(net.mask(), 0xffff_ffff);
1455 assert_eq!(net.mask_addr(), Ipv4Addr::new(0xff, 0xff, 0xff, 0xff));
1456
1457 let net = Ipv4Net::new("1.2.3.4".parse().unwrap(), 24).unwrap();
1458 assert_eq!(net.size(), Some(256));
1459 assert_eq!(net.width(), 24);
1460 assert_eq!(net.mask(), 0xffff_ff00);
1461 assert_eq!(net.mask_addr(), Ipv4Addr::new(0xff, 0xff, 0xff, 0));
1462
1463 let net = Ipv4Net::new("0.0.0.0".parse().unwrap(), 0).unwrap();
1464 assert_eq!(net.size(), None);
1465 assert_eq!(net.width(), 0);
1466 assert_eq!(net.mask(), 0);
1467 assert_eq!(net.mask_addr(), Ipv4Addr::new(0, 0, 0, 0));
1468
1469 let net = Ipv6Net::host_net("fd00:47::1".parse().unwrap());
1470 assert_eq!(net.size(), Some(1));
1471 assert_eq!(net.width(), 128);
1472 assert_eq!(net.mask(), 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff);
1473 assert_eq!(
1474 net.mask_addr(),
1475 Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)
1476 );
1477
1478 let net = Ipv6Net::new("fd00:47::1".parse().unwrap(), 56).unwrap();
1479 assert_eq!(net.size(), Some(0x0000_0000_0000_0100_0000_0000_0000_0000));
1480 assert_eq!(net.width(), 56);
1481 assert_eq!(net.mask(), 0xffff_ffff_ffff_ff00_0000_0000_0000_0000);
1482 assert_eq!(
1483 net.mask_addr(),
1484 Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0xff00, 0, 0, 0, 0)
1485 );
1486 }
1487
1488 #[test]
1489 fn test_iter() {
1490 let ipnet = Ipv4Net::new(Ipv4Addr::new(0, 0, 0, 0), 0).unwrap();
1491
1492 let actual = ipnet.addr_iter().take(5).collect::<Vec<_>>();
1493 let expected = (0..5).map(Ipv4Addr::from).collect::<Vec<_>>();
1494 assert_eq!(actual, expected);
1495
1496 let actual = ipnet.addr_iter().skip(5).take(10).collect::<Vec<_>>();
1497 let expected = (5..15).map(Ipv4Addr::from).collect::<Vec<_>>();
1498 assert_eq!(actual, expected);
1499
1500 let ipnet = Ipv6Net::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 0).unwrap();
1501
1502 let actual = ipnet.iter().take(5).collect::<Vec<_>>();
1503 let expected = (0..5).map(Ipv6Addr::from).collect::<Vec<_>>();
1504 assert_eq!(actual, expected);
1505
1506 let actual = ipnet.iter().skip(5).take(10).collect::<Vec<_>>();
1507 let expected = (5..15).map(Ipv6Addr::from).collect::<Vec<_>>();
1508 assert_eq!(actual, expected);
1509 }
1510
1511 #[test]
1512 fn test_contains() {
1513 let default_v4: IpNet = "0.0.0.0/0".parse().unwrap();
1514 let private_v4: IpNet = "10.0.0.0/8".parse().unwrap();
1515 let privater_v4_c0: IpNet = "10.0.0.0/9".parse().unwrap();
1516 let privater_v4_c1: IpNet = "10.128.0.0/9".parse().unwrap();
1517
1518 assert!(private_v4.is_subnet_of(&default_v4));
1519 assert!(privater_v4_c0.is_subnet_of(&default_v4));
1520 assert!(privater_v4_c0.is_subnet_of(&private_v4));
1521 assert!(privater_v4_c1.is_subnet_of(&default_v4));
1522 assert!(privater_v4_c1.is_subnet_of(&private_v4));
1523
1524 assert!(private_v4.is_supernet_of(&privater_v4_c0));
1525 assert!(private_v4.is_supernet_of(&privater_v4_c1));
1526
1527 assert!(!privater_v4_c0.overlaps(&privater_v4_c1));
1528 assert!(!privater_v4_c1.overlaps(&privater_v4_c0));
1529 assert!(privater_v4_c0.overlaps(&privater_v4_c0));
1530 assert!(privater_v4_c0.overlaps(&private_v4));
1531 assert!(private_v4.overlaps(&privater_v4_c0));
1532
1533 let child_ip: IpNet = "10.128.20.20/16".parse().unwrap();
1534 assert!(child_ip.is_subnet_of(&privater_v4_c1));
1535 assert!(!child_ip.is_subnet_of(&privater_v4_c0));
1536 }
1537
1538 #[test]
1539 fn test_is_network_addr() {
1540 let v4_net: IpNet = "127.0.0.0/8".parse().unwrap();
1541 let v4_host: IpNet = "127.0.0.1/8".parse().unwrap();
1542 let v6_net: IpNet = "fd00:1234:5678::/48".parse().unwrap();
1543 let v6_host: IpNet = "fd00:1234:5678::7777/48".parse().unwrap();
1544
1545 assert!(v4_net.is_network_address());
1546 assert!(!v4_host.is_network_address());
1547 assert!(v6_net.is_network_address());
1548 assert!(!v6_host.is_network_address());
1549
1550 let two_addr: IpNet = "10.7.7.64/31".parse().unwrap();
1553 let one_addr: IpNet = "10.7.7.64/32".parse().unwrap();
1554 assert!(two_addr.is_network_address());
1555 assert!(one_addr.is_network_address());
1556
1557 let unspec: IpNet = "0.0.0.0/0".parse().unwrap();
1560 assert!(unspec.is_network_address());
1561 }
1562
1563 #[test]
1564 fn test_is_multicast_with_scopes() {
1565 let v4_mcast: IpNet = "224.0.0.1/32".parse().unwrap();
1567 let v4_not_mcast: IpNet = "192.168.1.1/24".parse().unwrap();
1568
1569 assert!(v4_mcast.is_multicast());
1570 assert!(!v4_not_mcast.is_multicast());
1571
1572 let v6_mcast: IpNet = "ff02::1/128".parse().unwrap();
1574 let v6_not_mcast: IpNet = "2001:db8::1/64".parse().unwrap();
1575
1576 assert!(v6_mcast.is_multicast());
1577 assert!(!v6_not_mcast.is_multicast());
1578
1579 let v6_site_local_mcast: IpNet = "ff05::1/128".parse().unwrap();
1581 let v6_org_local_mcast: IpNet = "ff08::1/128".parse().unwrap();
1583 let v6_admin_local_mcast: IpNet = "ff04::1/128".parse().unwrap();
1585 let v6_link_local_mcast: IpNet = "ff02::1/128".parse().unwrap();
1587
1588 assert!(v6_admin_local_mcast.is_admin_scoped_multicast());
1590 assert!(v6_site_local_mcast.is_admin_scoped_multicast());
1591 assert!(v6_org_local_mcast.is_admin_scoped_multicast());
1592 assert!(!v6_link_local_mcast.is_admin_scoped_multicast()); assert!(!v6_not_mcast.is_admin_scoped_multicast());
1594
1595 let v4_admin_scoped: IpNet = "239.0.0.1/32".parse().unwrap();
1597 let v4_admin_scoped_range: IpNet = "239.192.0.0/16".parse().unwrap();
1598 assert!(v4_admin_scoped.is_admin_scoped_multicast());
1599 assert!(v4_admin_scoped_range.is_admin_scoped_multicast());
1600 assert!(!v4_mcast.is_admin_scoped_multicast());
1601
1602 assert!(!v6_site_local_mcast.is_admin_local_multicast());
1604 assert!(!v6_org_local_mcast.is_admin_local_multicast());
1605 assert!(v6_admin_local_mcast.is_admin_local_multicast());
1606 assert!(!v6_link_local_mcast.is_admin_local_multicast());
1607 assert!(!v6_not_mcast.is_admin_local_multicast());
1608 assert!(!v4_mcast.is_admin_local_multicast()); assert!(!v4_admin_scoped.is_admin_local_multicast()); let v4_local_mcast: IpNet = "239.255.0.1/32".parse().unwrap();
1613 let v4_local_mcast_range: IpNet = "239.255.128.0/24".parse().unwrap();
1614 let v4_not_local: IpNet = "239.254.255.255/32".parse().unwrap();
1615 assert!(v4_local_mcast.is_local_multicast());
1616 assert!(v4_local_mcast_range.is_local_multicast());
1617 assert!(!v4_not_local.is_local_multicast());
1618 assert!(!v4_mcast.is_local_multicast()); assert!(!v6_admin_local_mcast.is_local_multicast()); assert!(v6_site_local_mcast.is_site_local_multicast());
1623 assert!(!v6_org_local_mcast.is_site_local_multicast());
1624 assert!(!v6_admin_local_mcast.is_site_local_multicast());
1625 assert!(!v6_link_local_mcast.is_site_local_multicast());
1626 assert!(!v6_not_mcast.is_site_local_multicast());
1627 assert!(!v4_mcast.is_site_local_multicast());
1628
1629 assert!(!v6_site_local_mcast.is_org_local_multicast());
1632 assert!(v6_org_local_mcast.is_org_local_multicast());
1633 assert!(!v6_admin_local_mcast.is_org_local_multicast());
1634 assert!(!v6_link_local_mcast.is_org_local_multicast());
1635 assert!(!v6_not_mcast.is_org_local_multicast());
1636
1637 let v4_org_local_mcast: IpNet = "239.192.0.1/32".parse().unwrap();
1639 let v4_org_local_mcast_end: IpNet = "239.195.255.255/32".parse().unwrap();
1640 let v4_not_org_local: IpNet = "239.196.0.0/32".parse().unwrap();
1641 assert!(v4_org_local_mcast.is_org_local_multicast());
1642 assert!(v4_org_local_mcast_end.is_org_local_multicast());
1643 assert!(!v4_not_org_local.is_org_local_multicast());
1644 assert!(!v4_mcast.is_org_local_multicast()); }
1646
1647 #[test]
1648 fn test_ipv6_multicast_scope() {
1649 use MulticastScopeV6::*;
1650
1651 let link_local: Ipv6Net = "ff02::1/128".parse().unwrap();
1652 let admin_local: Ipv6Net = "ff04::1/128".parse().unwrap();
1653 let site_local: Ipv6Net = "ff05::1/128".parse().unwrap();
1654 let org_local: Ipv6Net = "ff08::1/128".parse().unwrap();
1655 let global: Ipv6Net = "ff0e::1/128".parse().unwrap();
1656 let not_mcast: Ipv6Net = "2001:db8::1/64".parse().unwrap();
1657
1658 assert_eq!(link_local.multicast_scope(), Some(LinkLocal));
1659 assert_eq!(admin_local.multicast_scope(), Some(AdminLocal));
1660 assert_eq!(site_local.multicast_scope(), Some(SiteLocal));
1661 assert_eq!(org_local.multicast_scope(), Some(OrganizationLocal));
1662 assert_eq!(global.multicast_scope(), Some(Global));
1663 assert_eq!(not_mcast.multicast_scope(), None);
1664
1665 assert!(!LinkLocal.is_admin_scoped_multicast());
1667 assert!(AdminLocal.is_admin_scoped_multicast());
1668 assert!(SiteLocal.is_admin_scoped_multicast());
1669 assert!(OrganizationLocal.is_admin_scoped_multicast());
1670 assert!(!Global.is_admin_scoped_multicast());
1671 }
1672
1673 #[cfg(feature = "ula")]
1674 #[test]
1675 fn test_ipv6_ula_builder() {
1676 let ula1 = UlaBuilder::default().build().unwrap();
1679 let ula2 = UlaBuilder::default().build().unwrap();
1680 assert_eq!(ula1.width(), 48);
1681 assert_ne!(ula1, ula2);
1682
1683 let t = SystemTime::now();
1686 let ula1 = UlaBuilder::default().date(t).build().unwrap();
1687 let ula2 = UlaBuilder::default().date(t).build().unwrap();
1688 assert_ne!(ula1, ula2);
1689
1690 let ula1 = UlaBuilder::default()
1693 .date(t)
1694 .id(vec![1, 2, 3, 4])
1695 .build()
1696 .unwrap();
1697 let ula2 = UlaBuilder::default()
1698 .date(t)
1699 .id(vec![1, 2, 3, 4])
1700 .build()
1701 .unwrap();
1702 assert_eq!(ula1, ula2);
1703 }
1704
1705 #[test]
1706 fn test_ipv6_resize() {
1707 let s56: Ipv6Net = "fd00:a:b:cc00::/56".parse().unwrap();
1708
1709 let s64 = s56.resize(64, 0xdd).unwrap();
1711 assert_eq!(s64, "fd00:a:b:ccdd::/64".parse().unwrap());
1712
1713 let s48 = s56.resize(48, 0).unwrap();
1715 assert_eq!(s48, "fd00:a:b::/48".parse().unwrap());
1716
1717 assert_eq!(s56.resize(200, 0), Result::Err(IpNetPrefixError(200)));
1719
1720 let s56: Ipv6Net = "fd00:a:b:ccdd::/56".parse().unwrap();
1722 let s64 = s56.resize(64, 0).unwrap();
1723 assert_eq!(s64, "fd00:a:b:ccdd::/64".parse().unwrap());
1724 let s64 = s56.resize(64, 0xff).unwrap();
1725 assert_eq!(s64, "fd00:a:b:ccff::/64".parse().unwrap());
1726 }
1727
1728 #[test]
1729 fn test_ipv4_resize() {
1730 let s16: Ipv4Net = "10.1.0.0/16".parse().unwrap();
1731
1732 let s24 = s16.resize(24, 2).unwrap();
1734 assert_eq!(s24, "10.1.2.0/24".parse().unwrap());
1735
1736 let s8 = s24.resize(8, 0).unwrap();
1738 assert_eq!(s8, "10.0.0.0/8".parse().unwrap());
1739
1740 assert_eq!(s16.resize(40, 0), Result::Err(IpNetPrefixError(40)));
1742
1743 let s16: Ipv4Net = "10.1.2.3/16".parse().unwrap();
1745 let s24 = s16.resize(24, 0).unwrap();
1747 assert_eq!(s24, "10.1.2.3/24".parse().unwrap());
1748 let s24 = s16.resize(24, 255).unwrap();
1749 assert_eq!(s24, "10.1.255.3/24".parse().unwrap());
1750 }
1751}