1use crate::error::IpNetworkError;
2use crate::parse::{cidr_parts, parse_prefix};
3use std::{convert::TryFrom, fmt, net::Ipv6Addr, str::FromStr};
4
5const IPV6_BITS: u8 = 128;
6const IPV6_SEGMENT_BITS: u8 = 16;
7
8#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
10pub struct Ipv6Network {
11 addr: Ipv6Addr,
12 prefix: u8,
13}
14
15#[cfg(feature = "serde")]
16impl<'de> serde::Deserialize<'de> for Ipv6Network {
17 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
18 where
19 D: serde::Deserializer<'de>,
20 {
21 let s = <String>::deserialize(deserializer)?;
22 Ipv6Network::from_str(&s).map_err(serde::de::Error::custom)
23 }
24}
25
26#[cfg(feature = "serde")]
27impl serde::Serialize for Ipv6Network {
28 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
29 where
30 S: serde::Serializer,
31 {
32 serializer.collect_str(self)
33 }
34}
35
36#[cfg(feature = "schemars")]
37impl schemars::JsonSchema for Ipv6Network {
38 fn schema_name() -> String {
39 "Ipv6Network".to_string()
40 }
41
42 fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
43 schemars::schema::SchemaObject {
44 instance_type: Some(schemars::schema::InstanceType::String.into()),
45 string: Some(Box::new(schemars::schema::StringValidation {
46 pattern: Some(
47 concat!(
48 r#"^("#,
49 r#"([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}"#,
50 r#"|([0-9a-fA-F]{1,4}:){1,7}:"#,
51 r#"|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}"#,
52 r#"|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}"#,
53 r#"|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}"#,
54 r#"|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}"#,
55 r#"|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}"#,
56 r#"|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})"#,
57 r#"|:((:[0-9a-fA-F]{1,4}){1,7}|:)"#,
58 r#"|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}"#,
59 r#"|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"#,
60 r#"|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"#,
61 r#"")[/](12[0-8]|1[0-1][0-9]|[0-9]?[0-9])$"#,
62 ).to_string(),
63 ),
64 ..Default::default()
65 })),
66 extensions: [("x-rust-type".to_string(), "ipnetwork::Ipv6Network".into())]
67 .iter()
68 .cloned()
69 .collect(),
70 ..Default::default()
71 }
72 .into()
73 }
74}
75
76impl Ipv6Network {
77 pub const fn new(addr: Ipv6Addr, prefix: u8) -> Result<Ipv6Network, IpNetworkError> {
81 match Ipv6Network::new_checked(addr, prefix) {
82 Some(a) => Ok(a),
83 None => Err(IpNetworkError::InvalidPrefix),
84 }
85 }
86
87 pub const fn new_checked(addr: Ipv6Addr, prefix: u8) -> Option<Ipv6Network> {
120 if prefix > IPV6_BITS {
121 None
122 } else {
123 Some(Ipv6Network { addr, prefix })
124 }
125 }
126
127 pub fn with_netmask(netaddr: Ipv6Addr, netmask: Ipv6Addr) -> Result<Self, IpNetworkError> {
131 let prefix = ipv6_mask_to_prefix(netmask)?;
132 let net = Self {
133 addr: netaddr,
134 prefix,
135 };
136 Ok(net)
137 }
138
139 pub fn iter(&self) -> Ipv6NetworkIterator {
147 let dec = u128::from(self.addr);
148 let max = u128::MAX;
149 let prefix = self.prefix;
150
151 let mask = max.checked_shl(u32::from(IPV6_BITS - prefix)).unwrap_or(0);
152 let start: u128 = dec & mask;
153
154 let mask = max.checked_shr(u32::from(prefix)).unwrap_or(0);
155 let end: u128 = dec | mask;
156
157 Ipv6NetworkIterator {
158 next: Some(start),
159 end,
160 }
161 }
162
163 pub fn ip(&self) -> Ipv6Addr {
164 self.addr
165 }
166
167 pub fn prefix(&self) -> u8 {
168 self.prefix
169 }
170
171 pub fn is_subnet_of(self, other: Ipv6Network) -> bool {
173 other.ip() <= self.ip() && other.broadcast() >= self.broadcast()
174 }
175
176 pub fn is_supernet_of(self, other: Ipv6Network) -> bool {
178 other.is_subnet_of(self)
179 }
180
181 pub fn overlaps(self, other: Ipv6Network) -> bool {
183 other.contains(self.ip())
184 || other.contains(self.broadcast())
185 || self.contains(other.ip())
186 || self.contains(other.broadcast())
187 }
188
189 pub fn mask(&self) -> Ipv6Addr {
204 debug_assert!(self.prefix <= IPV6_BITS);
205
206 if self.prefix == 0 {
207 return Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
208 }
209 let mask = u128::MAX << (IPV6_BITS - self.prefix);
210 Ipv6Addr::from(mask)
211 }
212
213 pub fn network(&self) -> Ipv6Addr {
226 let mask = u128::from(self.mask());
227 let network = u128::from(self.addr) & mask;
228 Ipv6Addr::from(network)
229 }
230
231 pub fn broadcast(&self) -> Ipv6Addr {
244 let mask = u128::from(self.mask());
245 let broadcast = u128::from(self.addr) | !mask;
246 Ipv6Addr::from(broadcast)
247 }
248
249 #[inline]
262 pub fn contains(&self, ip: Ipv6Addr) -> bool {
263 let ip = u128::from(ip);
264 let net = u128::from(self.network());
265 let mask = u128::from(self.mask());
266 (ip & mask) == net
267 }
268
269 pub fn size(&self) -> u128 {
284 debug_assert!(self.prefix <= IPV6_BITS);
285
286 if self.prefix == 0 {
287 return u128::MAX;
288 }
289 1 << (IPV6_BITS - self.prefix)
290 }
291
292 pub fn nth(self, n: u128) -> Option<Ipv6Addr> {
308 if n < self.size() {
309 let net = u128::from(self.network());
310 Some(Ipv6Addr::from(net + n))
311 } else {
312 None
313 }
314 }
315}
316
317impl FromStr for Ipv6Network {
331 type Err = IpNetworkError;
332 fn from_str(s: &str) -> Result<Self, Self::Err> {
333 let (addr_str, prefix_str) = cidr_parts(s)?;
334 let addr = Ipv6Addr::from_str(addr_str)?;
335 let prefix = parse_prefix(prefix_str.unwrap_or(&IPV6_BITS.to_string()), IPV6_BITS)?;
336 Ipv6Network::new(addr, prefix)
337 }
338}
339
340impl TryFrom<&str> for Ipv6Network {
341 type Error = IpNetworkError;
342
343 fn try_from(s: &str) -> Result<Self, Self::Error> {
344 Ipv6Network::from_str(s)
345 }
346}
347
348impl From<Ipv6Addr> for Ipv6Network {
349 fn from(a: Ipv6Addr) -> Ipv6Network {
350 Ipv6Network {
351 addr: a,
352 prefix: 128,
353 }
354 }
355}
356
357#[derive(Clone, Debug)]
358pub struct Ipv6NetworkIterator {
359 next: Option<u128>,
360 end: u128,
361}
362
363impl Iterator for Ipv6NetworkIterator {
364 type Item = Ipv6Addr;
365
366 fn next(&mut self) -> Option<Ipv6Addr> {
367 let next = self.next?;
368 self.next = if next == self.end {
369 None
370 } else {
371 Some(next + 1)
372 };
373 Some(next.into())
374 }
375}
376
377impl IntoIterator for &'_ Ipv6Network {
378 type IntoIter = Ipv6NetworkIterator;
379 type Item = Ipv6Addr;
380 fn into_iter(self) -> Ipv6NetworkIterator {
381 self.iter()
382 }
383}
384
385impl fmt::Display for Ipv6Network {
386 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
387 write!(fmt, "{}/{}", self.ip(), self.prefix())
388 }
389}
390
391pub fn ipv6_mask_to_prefix(mask: Ipv6Addr) -> Result<u8, IpNetworkError> {
394 let mask = mask.segments();
395 let mut mask_iter = mask.iter();
396
397 let mut prefix = 0;
399 for &segment in &mut mask_iter {
400 if segment == 0xffff {
401 prefix += IPV6_SEGMENT_BITS;
402 } else if segment == 0 {
403 break;
405 } else {
406 let prefix_bits = (!segment).leading_zeros() as u8;
407 if segment << prefix_bits != 0 {
409 return Err(IpNetworkError::InvalidPrefix);
410 }
411 prefix += prefix_bits;
412 break;
413 }
414 }
415
416 for &segment in mask_iter {
418 if segment != 0 {
419 return Err(IpNetworkError::InvalidPrefix);
420 }
421 }
422
423 Ok(prefix)
424}
425
426#[cfg(test)]
427mod test {
428 use super::*;
429 use std::collections::HashMap;
430 use std::net::Ipv6Addr;
431
432 #[test]
433 fn create_v6() {
434 let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 24).unwrap();
435 assert_eq!(cidr.prefix(), 24);
436 }
437
438 #[test]
439 fn parse_netmask_broken_v6() {
440 assert_eq!(
441 "FF01:0:0:17:0:0:0:2/255.255.255.0".parse::<Ipv6Network>(),
442 Err(IpNetworkError::InvalidPrefix)
443 );
444 }
445
446 #[test]
447 fn create_v6_invalid_prefix() {
448 let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 129);
449 assert!(cidr.is_err());
450 }
451
452 #[test]
453 fn create_checked_v6() {
454 let cidr = Ipv6Network::new_checked(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 24).unwrap();
455 assert_eq!(cidr.prefix(), 24);
456 }
457
458 #[test]
459 #[should_panic]
460 fn try_create_invalid_checked_v6() {
461 Ipv6Network::new_checked(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 129).unwrap();
462 }
463
464 #[test]
465 fn parse_v6() {
466 let cidr: Ipv6Network = "::1/0".parse().unwrap();
467 assert_eq!(cidr.ip(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
468 assert_eq!(cidr.prefix(), 0);
469 }
470
471 #[test]
472 fn parse_v6_2() {
473 let cidr: Ipv6Network = "FF01:0:0:17:0:0:0:2/64".parse().unwrap();
474 assert_eq!(cidr.ip(), Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2));
475 assert_eq!(cidr.prefix(), 64);
476 }
477
478 #[test]
479 fn parse_v6_noprefix() {
480 let cidr: Ipv6Network = "::1".parse().unwrap();
481 assert_eq!(cidr.ip(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
482 assert_eq!(cidr.prefix(), 128);
483 }
484
485 #[test]
486 fn parse_v6_fail_addr() {
487 let cidr: Option<Ipv6Network> = "2001::1::/8".parse().ok();
488 assert_eq!(None, cidr);
489 }
490
491 #[test]
492 fn parse_v6_fail_prefix() {
493 let cidr: Option<Ipv6Network> = "::1/129".parse().ok();
494 assert_eq!(None, cidr);
495 }
496
497 #[test]
498 fn parse_v6_fail_two_slashes() {
499 let cidr: Option<Ipv6Network> = "::1/24/".parse().ok();
500 assert_eq!(None, cidr);
501 }
502
503 #[test]
504 fn mask_v6() {
505 let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 40).unwrap();
506 let mask = cidr.mask();
507 assert_eq!(mask, Ipv6Addr::new(0xffff, 0xffff, 0xff00, 0, 0, 0, 0, 0));
508 }
509
510 #[test]
511 fn contains_v6() {
512 let cidr = Ipv6Network::new(Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2), 65).unwrap();
513 let ip = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0x7fff, 0, 0, 0x2);
514 assert!(cidr.contains(ip));
515 }
516
517 #[test]
518 fn not_contains_v6() {
519 let cidr = Ipv6Network::new(Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2), 65).unwrap();
520 let ip = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0xffff, 0, 0, 0x2);
521 assert!(!cidr.contains(ip));
522 }
523
524 #[test]
525 fn v6_mask_to_prefix() {
526 let mask = Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0, 0, 0, 0, 0);
527 let prefix = ipv6_mask_to_prefix(mask).unwrap();
528 assert_eq!(prefix, 48);
529 }
530
531 #[test]
532 fn invalid_v6_mask_to_prefix() {
533 let mask = Ipv6Addr::new(0, 0, 0xffff, 0xffff, 0, 0, 0, 0);
534 let prefix = ipv6_mask_to_prefix(mask);
535 assert!(prefix.is_err());
536 }
537
538 #[test]
539 fn ipv6network_with_netmask() {
540 {
541 let addr = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2);
543 let mask = Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0, 0, 0, 0, 0);
544 let net = Ipv6Network::with_netmask(addr, mask).unwrap();
545 let expected =
546 Ipv6Network::new(Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2), 48).unwrap();
547 assert_eq!(net, expected);
548 }
549 {
550 let addr = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2);
552 let mask = Ipv6Addr::new(0, 0, 0xffff, 0xffff, 0, 0, 0, 0);
553 Ipv6Network::with_netmask(addr, mask).unwrap_err();
554 }
555 }
556
557 #[test]
558 fn iterator_v6() {
559 let cidr: Ipv6Network = "2001:db8::/126".parse().unwrap();
560 let mut iter = cidr.iter();
561 assert_eq!(
562 Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
563 iter.next().unwrap()
564 );
565 assert_eq!(
566 Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1),
567 iter.next().unwrap()
568 );
569 assert_eq!(
570 Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 2),
571 iter.next().unwrap()
572 );
573 assert_eq!(
574 Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 3),
575 iter.next().unwrap()
576 );
577 assert_eq!(None, iter.next());
578 }
579
580 #[test]
581 fn iterator_v6_tiny() {
582 let cidr: Ipv6Network = "2001:db8::/128".parse().unwrap();
583 let mut iter = cidr.iter();
584 assert_eq!(
585 Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
586 iter.next().unwrap()
587 );
588 assert_eq!(None, iter.next());
589 }
590
591 #[test]
592 fn iterator_v6_huge() {
593 let cidr: Ipv6Network = "2001:db8::/0".parse().unwrap();
594 let mut iter = cidr.iter();
595 assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), iter.next().unwrap());
596 assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), iter.next().unwrap());
597 assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 2), iter.next().unwrap());
598 }
599
600 #[test]
601 fn network_v6() {
602 let cidr: Ipv6Network = "2001:db8::0/96".parse().unwrap();
603 let net = cidr.network();
604 let expected: Ipv6Addr = "2001:db8::".parse().unwrap();
605 assert_eq!(net, expected);
606 }
607
608 #[test]
609 fn broadcast_v6() {
610 let cidr: Ipv6Network = "2001:db8::0/96".parse().unwrap();
611 let net = cidr.broadcast();
612 let expected: Ipv6Addr = "2001:db8::ffff:ffff".parse().unwrap();
613 assert_eq!(net, expected);
614 }
615
616 #[test]
617 fn size_v6() {
618 let cidr: Ipv6Network = "2001:db8::0/96".parse().unwrap();
619 assert_eq!(cidr.size(), 4294967296);
620 }
621
622 #[test]
623 fn ipv6network_from_ipv6addr() {
624 let net = Ipv6Network::from(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
625 let expected = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 128).unwrap();
626 assert_eq!(net, expected);
627 }
628
629 #[test]
630 fn test_send() {
631 fn assert_send<T: Send>() {}
632 assert_send::<Ipv6Network>();
633 }
634
635 #[test]
636 fn test_sync() {
637 fn assert_sync<T: Sync>() {}
638 assert_sync::<Ipv6Network>();
639 }
640
641 #[test]
643 fn test_is_subnet_of() {
644 let mut test_cases: HashMap<(Ipv6Network, Ipv6Network), bool> = HashMap::new();
645
646 test_cases.insert(
647 (
648 "2000:999::/56".parse().unwrap(),
649 "2000:aaa::/48".parse().unwrap(),
650 ),
651 false,
652 );
653 test_cases.insert(
654 (
655 "2000:aaa::/56".parse().unwrap(),
656 "2000:aaa::/48".parse().unwrap(),
657 ),
658 true,
659 );
660 test_cases.insert(
661 (
662 "2000:bbb::/56".parse().unwrap(),
663 "2000:aaa::/48".parse().unwrap(),
664 ),
665 false,
666 );
667 test_cases.insert(
668 (
669 "2000:aaa::/48".parse().unwrap(),
670 "2000:aaa::/56".parse().unwrap(),
671 ),
672 false,
673 );
674
675 for (key, val) in test_cases.iter() {
676 let (src, dest) = (key.0, key.1);
677 assert_eq!(
678 src.is_subnet_of(dest),
679 *val,
680 "testing with {src} and {dest}"
681 );
682 }
683 }
684
685 #[test]
686 fn test_is_supernet_of() {
687 let mut test_cases: HashMap<(Ipv6Network, Ipv6Network), bool> = HashMap::new();
688
689 test_cases.insert(
690 (
691 "2000:999::/56".parse().unwrap(),
692 "2000:aaa::/48".parse().unwrap(),
693 ),
694 false,
695 );
696 test_cases.insert(
697 (
698 "2000:aaa::/56".parse().unwrap(),
699 "2000:aaa::/48".parse().unwrap(),
700 ),
701 false,
702 );
703 test_cases.insert(
704 (
705 "2000:bbb::/56".parse().unwrap(),
706 "2000:aaa::/48".parse().unwrap(),
707 ),
708 false,
709 );
710 test_cases.insert(
711 (
712 "2000:aaa::/48".parse().unwrap(),
713 "2000:aaa::/56".parse().unwrap(),
714 ),
715 true,
716 );
717
718 for (key, val) in test_cases.iter() {
719 let (src, dest) = (key.0, key.1);
720 assert_eq!(
721 src.is_supernet_of(dest),
722 *val,
723 "testing with {src} and {dest}"
724 );
725 }
726 }
727
728 #[test]
729 fn test_overlaps() {
730 let other: Ipv6Network = "2001:DB8:ACAD::1/64".parse().unwrap();
731 let other2: Ipv6Network = "2001:DB8:ACAD::20:2/64".parse().unwrap();
732
733 assert!(other2.overlaps(other));
734 }
735
736 #[test]
737 fn edges() {
738 let low: Ipv6Network = "::0/120".parse().unwrap();
739 let low_addrs: Vec<Ipv6Addr> = low.iter().collect();
740 assert_eq!(256, low_addrs.len());
741
742 let high: Ipv6Network = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00/120"
743 .parse()
744 .unwrap();
745 let high_addrs: Vec<Ipv6Addr> = high.iter().collect();
746 assert_eq!(256, high_addrs.len());
747 }
748
749 #[test]
750 fn test_nth_ipv6() {
751 let net = Ipv6Network::from_str("ff01::/32").unwrap();
752
753 assert_eq!(
754 net.nth(0).unwrap(),
755 Ipv6Addr::from_str("ff01:0:0:0:0:0:0:0").unwrap()
756 );
757 assert_eq!(
758 net.nth(255).unwrap(),
759 Ipv6Addr::from_str("ff01::ff").unwrap()
760 );
761 assert_eq!(
762 net.nth(65538).unwrap(),
763 Ipv6Addr::from_str("ff01::1:2").unwrap()
764 );
765 assert_eq!(net.nth(net.size()), None);
766 }
767
768 #[test]
769 fn test_mask_with_prefix_0() {
770 let network: Ipv6Network = "0::/0".parse().unwrap();
771 let mask = network.mask();
772 assert_eq!(mask, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
773 }
774
775 #[test]
776 fn test_size_with_prefix_0() {
777 let network: Ipv6Network = "0::/0".parse().unwrap();
778 assert_eq!(network.size(), u128::MAX);
779 }
780}