1use std::{
4 net::{AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr},
5 num::ParseIntError,
6};
7
8#[derive(Debug, Clone)]
10pub struct IpNetPrefixError(u8);
11
12impl std::fmt::Display for IpNetPrefixError {
13 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14 write!(f, "invalid network prefix {}", self.0)
15 }
16}
17impl std::error::Error for IpNetPrefixError {}
18
19#[derive(Debug, Clone)]
21pub enum IpNetParseError {
22 InvalidAddr(AddrParseError),
24 PrefixValue(IpNetPrefixError),
26 NoPrefix,
28 InvalidPrefix(ParseIntError),
30}
31
32impl std::fmt::Display for IpNetParseError {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 match self {
35 IpNetParseError::InvalidAddr(e) => e.fmt(f),
36 IpNetParseError::PrefixValue(e) => {
37 write!(f, "invalid prefix value: {e}")
38 }
39 IpNetParseError::NoPrefix => write!(f, "missing '/' character"),
40 IpNetParseError::InvalidPrefix(e) => e.fmt(f),
41 }
42 }
43}
44impl std::error::Error for IpNetParseError {}
45
46#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
48#[cfg_attr(feature = "serde", serde(untagged))]
49#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
50pub enum IpNet {
51 V4(Ipv4Net),
53 V6(Ipv6Net),
55}
56
57impl IpNet {
58 pub fn new(addr: IpAddr, prefix: u8) -> Result<Self, IpNetPrefixError> {
60 match addr {
61 IpAddr::V4(addr) => Ok(Self::V4(Ipv4Net::new(addr, prefix)?)),
62 IpAddr::V6(addr) => Ok(Self::V6(Ipv6Net::new(addr, prefix)?)),
63 }
64 }
65
66 pub const fn new_unchecked(addr: IpAddr, prefix: u8) -> Self {
69 match addr {
70 IpAddr::V4(addr) => Self::V4(Ipv4Net::new_unchecked(addr, prefix)),
71 IpAddr::V6(addr) => Self::V6(Ipv6Net::new_unchecked(addr, prefix)),
72 }
73 }
74
75 pub fn host_net(addr: IpAddr) -> Self {
77 match addr {
78 IpAddr::V4(addr) => Self::V4(Ipv4Net::host_net(addr)),
79 IpAddr::V6(addr) => Self::V6(Ipv6Net::host_net(addr)),
80 }
81 }
82
83 pub const fn addr(&self) -> IpAddr {
85 match self {
86 IpNet::V4(inner) => IpAddr::V4(inner.addr()),
87 IpNet::V6(inner) => IpAddr::V6(inner.addr()),
88 }
89 }
90
91 pub fn prefix(&self) -> IpAddr {
93 match self {
94 IpNet::V4(inner) => inner.prefix().into(),
95 IpNet::V6(inner) => inner.prefix().into(),
96 }
97 }
98
99 pub const fn width(&self) -> u8 {
101 match self {
102 IpNet::V4(inner) => inner.width(),
103 IpNet::V6(inner) => inner.width(),
104 }
105 }
106
107 pub fn mask_addr(&self) -> IpAddr {
109 match self {
110 IpNet::V4(inner) => inner.mask_addr().into(),
111 IpNet::V6(inner) => inner.mask_addr().into(),
112 }
113 }
114
115 pub const fn is_host_net(&self) -> bool {
118 match self {
119 IpNet::V4(inner) => inner.is_host_net(),
120 IpNet::V6(inner) => inner.is_host_net(),
121 }
122 }
123
124 pub fn is_network_address(&self) -> bool {
127 match self {
128 IpNet::V4(inner) => inner.is_network_address(),
129 IpNet::V6(inner) => inner.is_network_address(),
130 }
131 }
132
133 pub const fn is_multicast(&self) -> bool {
135 match self {
136 IpNet::V4(inner) => inner.is_multicast(),
137 IpNet::V6(inner) => inner.is_multicast(),
138 }
139 }
140
141 pub const fn is_admin_scoped_multicast(&self) -> bool {
158 match self {
159 IpNet::V4(inner) => inner.is_admin_scoped_multicast(),
160 IpNet::V6(inner) => inner.is_admin_scoped_multicast(),
161 }
162 }
163
164 pub const fn is_admin_local_multicast(&self) -> bool {
172 match self {
173 IpNet::V4(_inner) => false,
174 IpNet::V6(inner) => inner.is_admin_local_multicast(),
175 }
176 }
177
178 pub const fn is_local_multicast(&self) -> bool {
184 match self {
185 IpNet::V4(inner) => inner.is_local_multicast(),
186 IpNet::V6(_inner) => false,
187 }
188 }
189
190 pub const fn is_site_local_multicast(&self) -> bool {
197 match self {
198 IpNet::V4(_inner) => false,
199 IpNet::V6(inner) => inner.is_site_local_multicast(),
200 }
201 }
202
203 pub const fn is_org_local_multicast(&self) -> bool {
213 match self {
214 IpNet::V4(inner) => inner.is_org_local_multicast(),
215 IpNet::V6(inner) => inner.is_org_local_multicast(),
216 }
217 }
218
219 pub const fn is_unique_local(&self) -> bool {
222 match self {
223 IpNet::V4(_inner) => false, IpNet::V6(inner) => inner.is_unique_local(),
225 }
226 }
227
228 pub const fn is_loopback(&self) -> bool {
230 match self {
231 IpNet::V4(inner) => inner.is_loopback(),
232 IpNet::V6(inner) => inner.is_loopback(),
233 }
234 }
235
236 pub fn contains(&self, addr: IpAddr) -> bool {
241 match (self, addr) {
242 (IpNet::V4(net), IpAddr::V4(ip)) => net.contains(ip),
243 (IpNet::V6(net), IpAddr::V6(ip)) => net.contains(ip),
244 (_, _) => false,
245 }
246 }
247
248 pub fn is_subnet_of(&self, other: &Self) -> bool {
253 match (self, other) {
254 (IpNet::V4(net), IpNet::V4(other)) => net.is_subnet_of(other),
255 (IpNet::V6(net), IpNet::V6(other)) => net.is_subnet_of(other),
256 (_, _) => false,
257 }
258 }
259
260 pub fn is_supernet_of(&self, other: &Self) -> bool {
265 other.is_subnet_of(self)
266 }
267
268 pub fn overlaps(&self, other: &Self) -> bool {
273 match (self, other) {
274 (IpNet::V4(net), IpNet::V4(other)) => net.overlaps(other),
275 (IpNet::V6(net), IpNet::V6(other)) => net.overlaps(other),
276 (_, _) => false,
277 }
278 }
279
280 pub const fn is_ipv4(&self) -> bool {
282 matches!(self, IpNet::V4(_))
283 }
284
285 pub const fn is_ipv6(&self) -> bool {
287 matches!(self, IpNet::V6(_))
288 }
289}
290
291impl From<Ipv4Net> for IpNet {
292 fn from(n: Ipv4Net) -> IpNet {
293 IpNet::V4(n)
294 }
295}
296
297impl From<Ipv6Net> for IpNet {
298 fn from(n: Ipv6Net) -> IpNet {
299 IpNet::V6(n)
300 }
301}
302
303impl std::fmt::Display for IpNet {
304 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
305 match self {
306 IpNet::V4(inner) => write!(f, "{inner}"),
307 IpNet::V6(inner) => write!(f, "{inner}"),
308 }
309 }
310}
311
312impl std::str::FromStr for IpNet {
313 type Err = IpNetParseError;
314
315 fn from_str(s: &str) -> Result<Self, Self::Err> {
316 let Some((addr_str, prefix_str)) = s.split_once('/') else {
317 return Err(IpNetParseError::NoPrefix);
318 };
319
320 let prefix = prefix_str.parse().map_err(IpNetParseError::InvalidPrefix)?;
321 let addr = addr_str.parse().map_err(IpNetParseError::InvalidAddr)?;
322 IpNet::new(addr, prefix).map_err(IpNetParseError::PrefixValue)
323 }
324}
325
326#[cfg(feature = "schemars")]
327impl schemars::JsonSchema for IpNet {
328 fn schema_name() -> String {
329 "IpNet".to_string()
330 }
331
332 fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
333 use crate::schema_util::label_schema;
334 schemars::schema::SchemaObject {
335 subschemas: Some(Box::new(schemars::schema::SubschemaValidation {
336 one_of: Some(vec![
337 label_schema("v4", gen.subschema_for::<Ipv4Net>()),
338 label_schema("v6", gen.subschema_for::<Ipv6Net>()),
339 ]),
340 ..Default::default()
341 })),
342 extensions: crate::schema_util::extension("IpNet", "0.1.0"),
343 ..Default::default()
344 }
345 .into()
346 }
347}
348
349pub const IPV4_NET_WIDTH_MAX: u8 = 32;
351
352#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
354pub struct Ipv4Net {
355 addr: Ipv4Addr,
356 width: u8,
357}
358
359impl Ipv4Net {
360 pub fn new(addr: Ipv4Addr, width: u8) -> Result<Self, IpNetPrefixError> {
362 if width > IPV4_NET_WIDTH_MAX {
363 Err(IpNetPrefixError(width))
364 } else {
365 Ok(Self { addr, width })
366 }
367 }
368
369 pub const fn new_unchecked(addr: Ipv4Addr, width: u8) -> Self {
372 Self { addr, width }
373 }
374
375 pub const fn host_net(addr: Ipv4Addr) -> Self {
377 Self {
378 addr,
379 width: IPV4_NET_WIDTH_MAX,
380 }
381 }
382
383 pub const fn addr(&self) -> Ipv4Addr {
385 self.addr
386 }
387
388 pub const fn width(&self) -> u8 {
390 self.width
391 }
392
393 pub(crate) fn mask(&self) -> u32 {
394 u32::MAX
395 .checked_shl((IPV4_NET_WIDTH_MAX - self.width) as u32)
396 .unwrap_or(0)
397 }
398
399 pub fn mask_addr(&self) -> Ipv4Addr {
401 Ipv4Addr::from(self.mask())
402 }
403
404 pub const fn is_host_net(&self) -> bool {
407 self.width == IPV4_NET_WIDTH_MAX
408 }
409
410 pub fn is_network_address(&self) -> bool {
413 self.addr == self.prefix()
414 }
415
416 pub const fn is_multicast(&self) -> bool {
418 self.addr.is_multicast()
419 }
420
421 pub const fn is_admin_scoped_multicast(&self) -> bool {
430 self.addr.octets()[0] == 239
434 }
435
436 pub const fn is_local_multicast(&self) -> bool {
442 let octets = self.addr.octets();
444 octets[0] == 239 && octets[1] == 255
445 }
446
447 pub const fn is_org_local_multicast(&self) -> bool {
452 let octets = self.addr.octets();
455 octets[0] == 239 && (octets[1] >= 192 && octets[1] <= 195)
456 }
457
458 pub const fn is_loopback(&self) -> bool {
460 self.addr.is_loopback()
461 }
462
463 pub const fn size(&self) -> Option<u32> {
467 1u32.checked_shl((IPV4_NET_WIDTH_MAX - self.width) as u32)
468 }
469
470 pub fn prefix(&self) -> Ipv4Addr {
472 self.first_addr()
473 }
474
475 pub fn network(&self) -> Option<Ipv4Addr> {
478 (self.width < 31).then(|| self.first_addr())
479 }
480
481 pub fn broadcast(&self) -> Option<Ipv4Addr> {
484 (self.width < 31).then(|| self.last_addr())
485 }
486
487 pub fn first_addr(&self) -> Ipv4Addr {
489 let addr: u32 = self.addr.into();
490 Ipv4Addr::from(addr & self.mask())
491 }
492
493 pub fn last_addr(&self) -> Ipv4Addr {
495 let addr: u32 = self.addr.into();
496 Ipv4Addr::from(addr | !self.mask())
497 }
498
499 pub fn first_host(&self) -> Ipv4Addr {
503 let mask = self.mask();
504 let addr: u32 = self.addr.into();
505 let first = addr & mask;
506 if self.width == 31 || self.width == 32 {
507 Ipv4Addr::from(first)
508 } else {
509 Ipv4Addr::from(first + 1)
510 }
511 }
512
513 pub fn last_host(&self) -> Ipv4Addr {
518 let mask = self.mask();
519 let addr: u32 = self.addr.into();
520 let last = addr | !mask;
521 if self.width == 31 || self.width == 32 {
522 Ipv4Addr::from(last)
523 } else {
524 Ipv4Addr::from(last - 1)
525 }
526 }
527
528 pub fn contains(&self, other: Ipv4Addr) -> bool {
530 let mask = self.mask();
531 let addr: u32 = self.addr.into();
532 let other: u32 = other.into();
533
534 (addr & mask) == (other & mask)
535 }
536
537 pub fn nth(&self, n: usize) -> Option<Ipv4Addr> {
540 let addr: u32 = self.addr.into();
541 let nth = addr.checked_add(n.try_into().ok()?)?;
542 (nth <= self.last_addr().into()).then_some(nth.into())
543 }
544
545 pub fn addr_iter(&self) -> impl Iterator<Item = Ipv4Addr> {
547 Ipv4NetIter {
548 next: Some(self.first_addr().into()),
549 last: self.last_addr().into(),
550 }
551 }
552
553 pub fn host_iter(&self) -> impl Iterator<Item = Ipv4Addr> {
557 Ipv4NetIter {
558 next: Some(self.first_host().into()),
559 last: self.last_host().into(),
560 }
561 }
562
563 pub fn is_subnet_of(&self, other: &Self) -> bool {
565 other.first_addr() <= self.first_addr() && other.last_addr() >= self.last_addr()
566 }
567
568 pub fn is_supernet_of(&self, other: &Self) -> bool {
570 other.is_subnet_of(self)
571 }
572
573 pub fn overlaps(&self, other: &Self) -> bool {
576 let (parent, child) = if self.width <= other.width {
577 (self, other)
578 } else {
579 (other, self)
580 };
581
582 child.is_subnet_of(parent)
583 }
584}
585
586impl std::fmt::Display for Ipv4Net {
587 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
588 write!(f, "{}/{}", &self.addr, self.width)
589 }
590}
591
592impl std::str::FromStr for Ipv4Net {
593 type Err = IpNetParseError;
594
595 fn from_str(s: &str) -> Result<Self, Self::Err> {
596 let Some((addr_str, prefix_str)) = s.split_once('/') else {
597 return Err(IpNetParseError::NoPrefix);
598 };
599
600 let prefix = prefix_str.parse().map_err(IpNetParseError::InvalidPrefix)?;
601 let addr = addr_str.parse().map_err(IpNetParseError::InvalidAddr)?;
602 Ipv4Net::new(addr, prefix).map_err(IpNetParseError::PrefixValue)
603 }
604}
605
606#[cfg(feature = "serde")]
607impl<'de> serde::Deserialize<'de> for Ipv4Net {
608 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
609 where
610 D: serde::Deserializer<'de>,
611 {
612 String::deserialize(deserializer)?
613 .parse()
614 .map_err(<D::Error as serde::de::Error>::custom)
615 }
616}
617
618#[cfg(feature = "serde")]
619impl serde::Serialize for Ipv4Net {
620 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
621 where
622 S: serde::Serializer,
623 {
624 serializer.serialize_str(&format!("{self}"))
625 }
626}
627
628#[cfg(feature = "schemars")]
629const IPV4_NET_REGEX: &str = concat!(
630 r#"^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}"#,
631 r#"([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"#,
632 r#"/([0-9]|1[0-9]|2[0-9]|3[0-2])$"#,
633);
634
635#[cfg(feature = "schemars")]
636impl schemars::JsonSchema for Ipv4Net {
637 fn schema_name() -> String {
638 "Ipv4Net".to_string()
639 }
640
641 fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
642 schemars::schema::SchemaObject {
643 metadata: Some(Box::new(schemars::schema::Metadata {
644 title: Some("An IPv4 subnet".to_string()),
645 description: Some("An IPv4 subnet, including prefix and prefix length".to_string()),
646 examples: vec!["192.168.1.0/24".into()],
647 ..Default::default()
648 })),
649 instance_type: Some(schemars::schema::InstanceType::String.into()),
650 string: Some(Box::new(schemars::schema::StringValidation {
651 pattern: Some(IPV4_NET_REGEX.to_string()),
652 ..Default::default()
653 })),
654 extensions: crate::schema_util::extension("Ipv4Net", "0.1.0"),
655 ..Default::default()
656 }
657 .into()
658 }
659}
660
661pub const IPV6_NET_WIDTH_MAX: u8 = 128;
663
664#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
669#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
670pub enum MulticastScopeV6 {
671 InterfaceLocal = 0x1,
673 LinkLocal = 0x2,
675 AdminLocal = 0x4,
677 SiteLocal = 0x5,
679 OrganizationLocal = 0x8,
681 Global = 0xE,
683}
684
685impl MulticastScopeV6 {
686 pub const fn is_admin_scoped_multicast(&self) -> bool {
689 matches!(
690 self,
691 MulticastScopeV6::AdminLocal
692 | MulticastScopeV6::SiteLocal
693 | MulticastScopeV6::OrganizationLocal
694 )
695 }
696
697 pub const fn from_u8(scope: u8) -> Option<Self> {
700 match scope {
701 0x1 => Some(MulticastScopeV6::InterfaceLocal),
702 0x2 => Some(MulticastScopeV6::LinkLocal),
703 0x4 => Some(MulticastScopeV6::AdminLocal),
704 0x5 => Some(MulticastScopeV6::SiteLocal),
705 0x8 => Some(MulticastScopeV6::OrganizationLocal),
706 0xE => Some(MulticastScopeV6::Global),
707 _ => None,
708 }
709 }
710}
711
712#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
714pub struct Ipv6Net {
715 addr: Ipv6Addr,
716 width: u8,
717}
718
719impl Ipv6Net {
720 pub fn new(addr: Ipv6Addr, width: u8) -> Result<Self, IpNetPrefixError> {
722 if width > IPV6_NET_WIDTH_MAX {
723 Err(IpNetPrefixError(width))
724 } else {
725 Ok(Self { addr, width })
726 }
727 }
728
729 pub const fn new_unchecked(addr: Ipv6Addr, width: u8) -> Self {
732 Self { addr, width }
733 }
734
735 pub const fn host_net(addr: Ipv6Addr) -> Self {
737 Self {
738 addr,
739 width: IPV6_NET_WIDTH_MAX,
740 }
741 }
742
743 pub const fn addr(&self) -> Ipv6Addr {
745 self.addr
746 }
747
748 pub const fn width(&self) -> u8 {
750 self.width
751 }
752
753 pub(crate) fn mask(&self) -> u128 {
754 u128::MAX
755 .checked_shl((IPV6_NET_WIDTH_MAX - self.width) as u32)
756 .unwrap_or(0)
757 }
758
759 pub fn mask_addr(&self) -> Ipv6Addr {
761 Ipv6Addr::from(self.mask())
762 }
763
764 pub const fn is_host_net(&self) -> bool {
767 self.width == IPV6_NET_WIDTH_MAX
768 }
769
770 pub fn is_network_address(&self) -> bool {
773 self.addr == self.prefix()
774 }
775
776 pub const fn is_multicast(&self) -> bool {
778 self.addr.is_multicast()
779 }
780
781 pub const fn multicast_scope(&self) -> Option<MulticastScopeV6> {
788 if !self.addr.is_multicast() {
789 return None;
790 }
791
792 let segments = self.addr.segments();
794 let scope = (segments[0] & 0x000F) as u8;
795
796 MulticastScopeV6::from_u8(scope)
797 }
798
799 pub const fn is_admin_scoped_multicast(&self) -> bool {
813 match self.multicast_scope() {
814 Some(scope) => scope.is_admin_scoped_multicast(),
815 None => false,
816 }
817 }
818
819 pub const fn is_admin_local_multicast(&self) -> bool {
825 matches!(self.multicast_scope(), Some(MulticastScopeV6::AdminLocal))
826 }
827
828 pub const fn is_site_local_multicast(&self) -> bool {
834 matches!(self.multicast_scope(), Some(MulticastScopeV6::SiteLocal))
835 }
836
837 pub const fn is_org_local_multicast(&self) -> bool {
843 matches!(
844 self.multicast_scope(),
845 Some(MulticastScopeV6::OrganizationLocal)
846 )
847 }
848
849 pub const fn is_loopback(&self) -> bool {
851 self.addr.is_loopback()
852 }
853
854 pub const fn size(&self) -> Option<u128> {
858 1u128.checked_shl((IPV6_NET_WIDTH_MAX - self.width) as u32)
859 }
860
861 pub fn prefix(&self) -> Ipv6Addr {
863 self.first_addr()
864 }
865
866 pub const fn is_unique_local(&self) -> bool {
871 self.addr.is_unique_local()
872 }
873
874 pub fn first_addr(&self) -> Ipv6Addr {
876 let addr: u128 = self.addr.into();
877 Ipv6Addr::from(addr & self.mask())
878 }
879
880 pub fn last_addr(&self) -> Ipv6Addr {
882 let addr: u128 = self.addr.into();
883 Ipv6Addr::from(addr | !self.mask())
884 }
885
886 pub fn iter(&self) -> impl Iterator<Item = Ipv6Addr> {
888 Ipv6NetIter {
889 next: Some(self.first_addr().into()),
890 last: self.last_addr().into(),
891 }
892 }
893
894 pub fn contains(&self, other: Ipv6Addr) -> bool {
896 let mask = self.mask();
897 let addr: u128 = self.addr.into();
898 let other: u128 = other.into();
899
900 (addr & mask) == (other & mask)
901 }
902
903 pub fn nth(&self, n: u128) -> Option<Ipv6Addr> {
906 let addr: u128 = self.addr.into();
907 let nth = addr.checked_add(n)?;
908 (nth <= self.last_addr().into()).then_some(nth.into())
909 }
910
911 pub fn is_subnet_of(&self, other: &Self) -> bool {
913 other.first_addr() <= self.first_addr() && other.last_addr() >= self.last_addr()
914 }
915
916 pub fn is_supernet_of(&self, other: &Self) -> bool {
918 other.is_subnet_of(self)
919 }
920
921 pub fn overlaps(&self, other: &Self) -> bool {
924 let (parent, child) = if self.width <= other.width {
925 (self, other)
926 } else {
927 (other, self)
928 };
929
930 child.is_subnet_of(parent)
931 }
932}
933
934impl std::fmt::Display for Ipv6Net {
935 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
936 write!(f, "{}/{}", &self.addr, self.width)
937 }
938}
939
940impl std::str::FromStr for Ipv6Net {
941 type Err = IpNetParseError;
942
943 fn from_str(s: &str) -> Result<Self, Self::Err> {
944 let Some((addr_str, prefix_str)) = s.split_once('/') else {
945 return Err(IpNetParseError::NoPrefix);
946 };
947
948 let prefix = prefix_str.parse().map_err(IpNetParseError::InvalidPrefix)?;
949 let addr = addr_str.parse().map_err(IpNetParseError::InvalidAddr)?;
950 Ipv6Net::new(addr, prefix).map_err(IpNetParseError::PrefixValue)
951 }
952}
953
954#[cfg(feature = "serde")]
955impl<'de> serde::Deserialize<'de> for Ipv6Net {
956 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
957 where
958 D: serde::Deserializer<'de>,
959 {
960 String::deserialize(deserializer)?
961 .parse()
962 .map_err(<D::Error as serde::de::Error>::custom)
963 }
964}
965
966#[cfg(feature = "serde")]
967impl serde::Serialize for Ipv6Net {
968 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
969 where
970 S: serde::Serializer,
971 {
972 serializer.serialize_str(&format!("{self}"))
973 }
974}
975
976#[cfg(feature = "schemars")]
977const IPV6_NET_REGEX: &str = concat!(
978 r#"^("#,
979 r#"([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|"#,
980 r#"([0-9a-fA-F]{1,4}:){1,7}:|"#,
981 r#"([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|"#,
982 r#"([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|"#,
983 r#"([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|"#,
984 r#"([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|"#,
985 r#"([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|"#,
986 r#"[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|"#,
987 r#":((:[0-9a-fA-F]{1,4}){1,7}|:)|"#,
988 r#"fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|"#,
989 r#"::(ffff(:0{1,4}){0,1}:){0,1}"#,
990 r#"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}"#,
991 r#"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|"#,
992 r#"([0-9a-fA-F]{1,4}:){1,4}:"#,
993 r#"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}"#,
994 r#"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"#,
995 r#")\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$"#,
996);
997
998#[cfg(feature = "schemars")]
999impl schemars::JsonSchema for Ipv6Net {
1000 fn schema_name() -> String {
1001 "Ipv6Net".to_string()
1002 }
1003
1004 fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
1005 schemars::schema::SchemaObject {
1006 metadata: Some(Box::new(schemars::schema::Metadata {
1007 title: Some("An IPv6 subnet".to_string()),
1008 description: Some("An IPv6 subnet, including prefix and subnet mask".to_string()),
1009 examples: vec!["fd12:3456::/64".into()],
1010 ..Default::default()
1011 })),
1012 instance_type: Some(schemars::schema::InstanceType::String.into()),
1013 string: Some(Box::new(schemars::schema::StringValidation {
1014 pattern: Some(IPV6_NET_REGEX.to_string()),
1015 ..Default::default()
1016 })),
1017 extensions: crate::schema_util::extension("Ipv6Net", "0.1.0"),
1018 ..Default::default()
1019 }
1020 .into()
1021 }
1022}
1023
1024pub struct Ipv4NetIter {
1025 next: Option<u32>,
1026 last: u32,
1027}
1028
1029impl Iterator for Ipv4NetIter {
1030 type Item = Ipv4Addr;
1031
1032 fn next(&mut self) -> Option<Self::Item> {
1033 let next = self.next?;
1034 if next == self.last {
1035 self.next = None;
1036 } else {
1037 self.next = Some(next + 1)
1038 }
1039 Some(next.into())
1040 }
1041
1042 fn nth(&mut self, n: usize) -> Option<Self::Item> {
1043 let next = self.next?;
1044 let nth = next.checked_add(n as u32)?;
1045 self.next = (nth <= self.last).then_some(nth);
1046 self.next()
1047 }
1048}
1049
1050pub struct Ipv6NetIter {
1051 next: Option<u128>,
1052 last: u128,
1053}
1054
1055impl Iterator for Ipv6NetIter {
1056 type Item = Ipv6Addr;
1057
1058 fn next(&mut self) -> Option<Self::Item> {
1059 let next = self.next?;
1060 if next == self.last {
1061 self.next = None;
1062 } else {
1063 self.next = Some(next + 1)
1064 }
1065 Some(next.into())
1066 }
1067
1068 fn nth(&mut self, n: usize) -> Option<Self::Item> {
1069 let next = self.next?;
1070 let nth = next.checked_add(n as u128)?;
1071 self.next = (nth <= self.last).then_some(nth);
1072 self.next()
1073 }
1074}
1075
1076#[cfg(feature = "ipnetwork")]
1077mod ipnetwork_feature {
1078 use super::*;
1079 use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network};
1080
1081 impl From<IpNetwork> for IpNet {
1082 fn from(value: IpNetwork) -> Self {
1083 match value {
1084 IpNetwork::V4(net) => Self::V4(net.into()),
1085 IpNetwork::V6(net) => Self::V6(net.into()),
1086 }
1087 }
1088 }
1089
1090 impl From<IpNet> for IpNetwork {
1091 fn from(value: IpNet) -> Self {
1092 match value {
1093 IpNet::V4(net) => Self::V4(net.into()),
1094 IpNet::V6(net) => Self::V6(net.into()),
1095 }
1096 }
1097 }
1098
1099 impl From<Ipv4Network> for Ipv4Net {
1100 fn from(value: Ipv4Network) -> Self {
1101 Self {
1102 addr: value.ip(),
1103 width: value.prefix(),
1104 }
1105 }
1106 }
1107
1108 impl From<Ipv4Net> for Ipv4Network {
1109 fn from(value: Ipv4Net) -> Self {
1110 Self::new(value.addr, value.width).unwrap()
1111 }
1112 }
1113
1114 impl From<Ipv6Network> for Ipv6Net {
1115 fn from(value: Ipv6Network) -> Self {
1116 Self {
1117 addr: value.ip(),
1118 width: value.prefix(),
1119 }
1120 }
1121 }
1122
1123 impl From<Ipv6Net> for Ipv6Network {
1124 fn from(value: Ipv6Net) -> Self {
1125 Self::new(value.addr, value.width).unwrap()
1126 }
1127 }
1128}
1129
1130#[cfg(test)]
1131mod tests {
1132 use super::*;
1133
1134 #[test]
1135 fn test_ipv6_regex() {
1136 let re = regress::Regex::new(IPV6_NET_REGEX).unwrap();
1137 for case in [
1138 "1:2:3:4:5:6:7:8",
1139 "1:a:2:b:3:c:4:d",
1140 "1::",
1141 "::1",
1142 "::",
1143 "1::3:4:5:6:7:8",
1144 "1:2::4:5:6:7:8",
1145 "1:2:3::5:6:7:8",
1146 "1:2:3:4::6:7:8",
1147 "1:2:3:4:5::7:8",
1148 "1:2:3:4:5:6::8",
1149 "1:2:3:4:5:6:7::",
1150 "2001::",
1151 "fd00::",
1152 "::100:1",
1153 "fd12:3456::",
1154 ] {
1155 for prefix in 0..=128 {
1156 let net = format!("{case}/{prefix}");
1157 assert!(
1158 re.find(&net).is_some(),
1159 "Expected to match IPv6 case: {}",
1160 prefix,
1161 );
1162 }
1163 }
1164 }
1165
1166 #[test]
1167 fn test_ipv4_net_operations() {
1168 let x: IpNet = "0.0.0.0/0".parse().unwrap();
1169 assert_eq!(x, IpNet::V4("0.0.0.0/0".parse().unwrap()));
1170 }
1171
1172 #[test]
1173 fn test_ipnet_serde() {
1174 let net_str = "fd00:2::/32";
1175 let net: IpNet = net_str.parse().unwrap();
1176 let ser = serde_json::to_string(&net).unwrap();
1177
1178 assert_eq!(format!(r#""{}""#, net_str), ser);
1179 let net_des = serde_json::from_str::<IpNet>(&ser).unwrap();
1180 assert_eq!(net, net_des);
1181
1182 let net_str = "fd00:47::1/64";
1183 let net: IpNet = net_str.parse().unwrap();
1184 let ser = serde_json::to_string(&net).unwrap();
1185
1186 assert_eq!(format!(r#""{}""#, net_str), ser);
1187 let net_des = serde_json::from_str::<IpNet>(&ser).unwrap();
1188 assert_eq!(net, net_des);
1189
1190 let net_str = "192.168.1.1/16";
1191 let net: IpNet = net_str.parse().unwrap();
1192 let ser = serde_json::to_string(&net).unwrap();
1193
1194 assert_eq!(format!(r#""{}""#, net_str), ser);
1195 let net_des = serde_json::from_str::<IpNet>(&ser).unwrap();
1196 assert_eq!(net, net_des);
1197
1198 let net_str = "0.0.0.0/0";
1199 let net: IpNet = net_str.parse().unwrap();
1200 let ser = serde_json::to_string(&net).unwrap();
1201
1202 assert_eq!(format!(r#""{}""#, net_str), ser);
1203 let net_des = serde_json::from_str::<IpNet>(&ser).unwrap();
1204 assert_eq!(net, net_des);
1205 }
1206
1207 #[test]
1208 fn test_ipnet_size() {
1209 let net = Ipv4Net::host_net("1.2.3.4".parse().unwrap());
1210 assert_eq!(net.size(), Some(1));
1211 assert_eq!(net.width(), 32);
1212 assert_eq!(net.mask(), 0xffff_ffff);
1213 assert_eq!(net.mask_addr(), Ipv4Addr::new(0xff, 0xff, 0xff, 0xff));
1214
1215 let net = Ipv4Net::new("1.2.3.4".parse().unwrap(), 24).unwrap();
1216 assert_eq!(net.size(), Some(256));
1217 assert_eq!(net.width(), 24);
1218 assert_eq!(net.mask(), 0xffff_ff00);
1219 assert_eq!(net.mask_addr(), Ipv4Addr::new(0xff, 0xff, 0xff, 0));
1220
1221 let net = Ipv4Net::new("0.0.0.0".parse().unwrap(), 0).unwrap();
1222 assert_eq!(net.size(), None);
1223 assert_eq!(net.width(), 0);
1224 assert_eq!(net.mask(), 0);
1225 assert_eq!(net.mask_addr(), Ipv4Addr::new(0, 0, 0, 0));
1226
1227 let net = Ipv6Net::host_net("fd00:47::1".parse().unwrap());
1228 assert_eq!(net.size(), Some(1));
1229 assert_eq!(net.width(), 128);
1230 assert_eq!(net.mask(), 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff);
1231 assert_eq!(
1232 net.mask_addr(),
1233 Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)
1234 );
1235
1236 let net = Ipv6Net::new("fd00:47::1".parse().unwrap(), 56).unwrap();
1237 assert_eq!(net.size(), Some(0x0000_0000_0000_0100_0000_0000_0000_0000));
1238 assert_eq!(net.width(), 56);
1239 assert_eq!(net.mask(), 0xffff_ffff_ffff_ff00_0000_0000_0000_0000);
1240 assert_eq!(
1241 net.mask_addr(),
1242 Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0xff00, 0, 0, 0, 0)
1243 );
1244 }
1245
1246 #[test]
1247 fn test_iter() {
1248 let ipnet = Ipv4Net::new(Ipv4Addr::new(0, 0, 0, 0), 0).unwrap();
1249
1250 let actual = ipnet.addr_iter().take(5).collect::<Vec<_>>();
1251 let expected = (0..5).map(Ipv4Addr::from).collect::<Vec<_>>();
1252 assert_eq!(actual, expected);
1253
1254 let actual = ipnet.addr_iter().skip(5).take(10).collect::<Vec<_>>();
1255 let expected = (5..15).map(Ipv4Addr::from).collect::<Vec<_>>();
1256 assert_eq!(actual, expected);
1257
1258 let ipnet = Ipv6Net::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 0).unwrap();
1259
1260 let actual = ipnet.iter().take(5).collect::<Vec<_>>();
1261 let expected = (0..5).map(Ipv6Addr::from).collect::<Vec<_>>();
1262 assert_eq!(actual, expected);
1263
1264 let actual = ipnet.iter().skip(5).take(10).collect::<Vec<_>>();
1265 let expected = (5..15).map(Ipv6Addr::from).collect::<Vec<_>>();
1266 assert_eq!(actual, expected);
1267 }
1268
1269 #[test]
1270 fn test_contains() {
1271 let default_v4: IpNet = "0.0.0.0/0".parse().unwrap();
1272 let private_v4: IpNet = "10.0.0.0/8".parse().unwrap();
1273 let privater_v4_c0: IpNet = "10.0.0.0/9".parse().unwrap();
1274 let privater_v4_c1: IpNet = "10.128.0.0/9".parse().unwrap();
1275
1276 assert!(private_v4.is_subnet_of(&default_v4));
1277 assert!(privater_v4_c0.is_subnet_of(&default_v4));
1278 assert!(privater_v4_c0.is_subnet_of(&private_v4));
1279 assert!(privater_v4_c1.is_subnet_of(&default_v4));
1280 assert!(privater_v4_c1.is_subnet_of(&private_v4));
1281
1282 assert!(private_v4.is_supernet_of(&privater_v4_c0));
1283 assert!(private_v4.is_supernet_of(&privater_v4_c1));
1284
1285 assert!(!privater_v4_c0.overlaps(&privater_v4_c1));
1286 assert!(!privater_v4_c1.overlaps(&privater_v4_c0));
1287 assert!(privater_v4_c0.overlaps(&privater_v4_c0));
1288 assert!(privater_v4_c0.overlaps(&private_v4));
1289 assert!(private_v4.overlaps(&privater_v4_c0));
1290
1291 let child_ip: IpNet = "10.128.20.20/16".parse().unwrap();
1292 assert!(child_ip.is_subnet_of(&privater_v4_c1));
1293 assert!(!child_ip.is_subnet_of(&privater_v4_c0));
1294 }
1295
1296 #[test]
1297 fn test_is_network_addr() {
1298 let v4_net: IpNet = "127.0.0.0/8".parse().unwrap();
1299 let v4_host: IpNet = "127.0.0.1/8".parse().unwrap();
1300 let v6_net: IpNet = "fd00:1234:5678::/48".parse().unwrap();
1301 let v6_host: IpNet = "fd00:1234:5678::7777/48".parse().unwrap();
1302
1303 assert!(v4_net.is_network_address());
1304 assert!(!v4_host.is_network_address());
1305 assert!(v6_net.is_network_address());
1306 assert!(!v6_host.is_network_address());
1307
1308 let two_addr: IpNet = "10.7.7.64/31".parse().unwrap();
1311 let one_addr: IpNet = "10.7.7.64/32".parse().unwrap();
1312 assert!(two_addr.is_network_address());
1313 assert!(one_addr.is_network_address());
1314
1315 let unspec: IpNet = "0.0.0.0/0".parse().unwrap();
1318 assert!(unspec.is_network_address());
1319 }
1320
1321 #[test]
1322 fn test_is_multicast_with_scopes() {
1323 let v4_mcast: IpNet = "224.0.0.1/32".parse().unwrap();
1325 let v4_not_mcast: IpNet = "192.168.1.1/24".parse().unwrap();
1326
1327 assert!(v4_mcast.is_multicast());
1328 assert!(!v4_not_mcast.is_multicast());
1329
1330 let v6_mcast: IpNet = "ff02::1/128".parse().unwrap();
1332 let v6_not_mcast: IpNet = "2001:db8::1/64".parse().unwrap();
1333
1334 assert!(v6_mcast.is_multicast());
1335 assert!(!v6_not_mcast.is_multicast());
1336
1337 let v6_site_local_mcast: IpNet = "ff05::1/128".parse().unwrap();
1339 let v6_org_local_mcast: IpNet = "ff08::1/128".parse().unwrap();
1341 let v6_admin_local_mcast: IpNet = "ff04::1/128".parse().unwrap();
1343 let v6_link_local_mcast: IpNet = "ff02::1/128".parse().unwrap();
1345
1346 assert!(v6_admin_local_mcast.is_admin_scoped_multicast());
1348 assert!(v6_site_local_mcast.is_admin_scoped_multicast());
1349 assert!(v6_org_local_mcast.is_admin_scoped_multicast());
1350 assert!(!v6_link_local_mcast.is_admin_scoped_multicast()); assert!(!v6_not_mcast.is_admin_scoped_multicast());
1352
1353 let v4_admin_scoped: IpNet = "239.0.0.1/32".parse().unwrap();
1355 let v4_admin_scoped_range: IpNet = "239.192.0.0/16".parse().unwrap();
1356 assert!(v4_admin_scoped.is_admin_scoped_multicast());
1357 assert!(v4_admin_scoped_range.is_admin_scoped_multicast());
1358 assert!(!v4_mcast.is_admin_scoped_multicast());
1359
1360 assert!(!v6_site_local_mcast.is_admin_local_multicast());
1362 assert!(!v6_org_local_mcast.is_admin_local_multicast());
1363 assert!(v6_admin_local_mcast.is_admin_local_multicast());
1364 assert!(!v6_link_local_mcast.is_admin_local_multicast());
1365 assert!(!v6_not_mcast.is_admin_local_multicast());
1366 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();
1371 let v4_local_mcast_range: IpNet = "239.255.128.0/24".parse().unwrap();
1372 let v4_not_local: IpNet = "239.254.255.255/32".parse().unwrap();
1373 assert!(v4_local_mcast.is_local_multicast());
1374 assert!(v4_local_mcast_range.is_local_multicast());
1375 assert!(!v4_not_local.is_local_multicast());
1376 assert!(!v4_mcast.is_local_multicast()); assert!(!v6_admin_local_mcast.is_local_multicast()); assert!(v6_site_local_mcast.is_site_local_multicast());
1381 assert!(!v6_org_local_mcast.is_site_local_multicast());
1382 assert!(!v6_admin_local_mcast.is_site_local_multicast());
1383 assert!(!v6_link_local_mcast.is_site_local_multicast());
1384 assert!(!v6_not_mcast.is_site_local_multicast());
1385 assert!(!v4_mcast.is_site_local_multicast());
1386
1387 assert!(!v6_site_local_mcast.is_org_local_multicast());
1390 assert!(v6_org_local_mcast.is_org_local_multicast());
1391 assert!(!v6_admin_local_mcast.is_org_local_multicast());
1392 assert!(!v6_link_local_mcast.is_org_local_multicast());
1393 assert!(!v6_not_mcast.is_org_local_multicast());
1394
1395 let v4_org_local_mcast: IpNet = "239.192.0.1/32".parse().unwrap();
1397 let v4_org_local_mcast_end: IpNet = "239.195.255.255/32".parse().unwrap();
1398 let v4_not_org_local: IpNet = "239.196.0.0/32".parse().unwrap();
1399 assert!(v4_org_local_mcast.is_org_local_multicast());
1400 assert!(v4_org_local_mcast_end.is_org_local_multicast());
1401 assert!(!v4_not_org_local.is_org_local_multicast());
1402 assert!(!v4_mcast.is_org_local_multicast()); }
1404
1405 #[test]
1406 fn test_ipv6_multicast_scope() {
1407 use MulticastScopeV6::*;
1408
1409 let link_local: Ipv6Net = "ff02::1/128".parse().unwrap();
1410 let admin_local: Ipv6Net = "ff04::1/128".parse().unwrap();
1411 let site_local: Ipv6Net = "ff05::1/128".parse().unwrap();
1412 let org_local: Ipv6Net = "ff08::1/128".parse().unwrap();
1413 let global: Ipv6Net = "ff0e::1/128".parse().unwrap();
1414 let not_mcast: Ipv6Net = "2001:db8::1/64".parse().unwrap();
1415
1416 assert_eq!(link_local.multicast_scope(), Some(LinkLocal));
1417 assert_eq!(admin_local.multicast_scope(), Some(AdminLocal));
1418 assert_eq!(site_local.multicast_scope(), Some(SiteLocal));
1419 assert_eq!(org_local.multicast_scope(), Some(OrganizationLocal));
1420 assert_eq!(global.multicast_scope(), Some(Global));
1421 assert_eq!(not_mcast.multicast_scope(), None);
1422
1423 assert!(!LinkLocal.is_admin_scoped_multicast());
1425 assert!(AdminLocal.is_admin_scoped_multicast());
1426 assert!(SiteLocal.is_admin_scoped_multicast());
1427 assert!(OrganizationLocal.is_admin_scoped_multicast());
1428 assert!(!Global.is_admin_scoped_multicast());
1429 }
1430}