1use crate::ipv4_utils::ipv4_summarize_range;
2use ipnet::{IpNet, Ipv4Net, Ipv6Net};
3use std::cmp::{max, min};
4use std::collections::BTreeSet;
5use std::net::Ipv6Addr;
6
7pub fn find_overlaps(country_ips: &BTreeSet<IpNet>, as_ips: &BTreeSet<IpNet>) -> BTreeSet<IpNet> {
10 let mut result = BTreeSet::new();
11
12 for cnet in country_ips {
13 for anet in as_ips {
14 let overlap_cidrs = ipnet_overlap(cnet, anet);
15 result.extend(overlap_cidrs);
16 }
17 }
18 result
19}
20
21fn ipnet_overlap(a: &IpNet, b: &IpNet) -> Vec<IpNet> {
24 match (a, b) {
25 (IpNet::V4(a4), IpNet::V4(b4)) => ipv4_overlap(a4, b4),
26 (IpNet::V6(a6), IpNet::V6(b6)) => ipv6_overlap(a6, b6),
27 _ => Vec::new(),
29 }
30}
31
32fn ipv4_overlap(a: &Ipv4Net, b: &Ipv4Net) -> Vec<IpNet> {
34 let a_start = u32::from(a.network());
35 let a_end = u32::from(a.broadcast());
36 let b_start = u32::from(b.network());
37 let b_end = u32::from(b.broadcast());
38
39 let overlap_start = max(a_start, b_start);
40 let overlap_end = min(a_end, b_end);
41 if overlap_start > overlap_end {
42 return Vec::new();
43 }
44
45 ipv4_summarize_range(overlap_start, overlap_end)
47}
48
49fn ipv6_overlap(a: &Ipv6Net, b: &Ipv6Net) -> Vec<IpNet> {
51 let a_start = ipv6_to_u128(a.network());
52 let a_end = ipv6_to_u128(a.broadcast());
53 let b_start = ipv6_to_u128(b.network());
54 let b_end = ipv6_to_u128(b.broadcast());
55
56 let overlap_start = max(a_start, b_start);
57 let overlap_end = min(a_end, b_end);
58 if overlap_start > overlap_end {
59 return Vec::new();
60 }
61
62 ipv6_summarize_range(overlap_start, overlap_end)
63}
64
65fn ipv6_summarize_range(start: u128, end: u128) -> Vec<IpNet> {
67 let mut cidrs = Vec::new();
68 let mut current = start;
69
70 while current <= end {
71 let max_size = largest_ipv6_block_in_overlap(current, end);
72 if let Ok(net) = Ipv6Net::new(Ipv6Addr::from(current), max_size) {
73 cidrs.push(IpNet::V6(net));
74 let block_size = 1u128 << (128 - max_size);
75 current = current.saturating_add(block_size);
76 } else {
77 break;
78 }
79 }
80
81 cidrs
82}
83
84fn largest_ipv6_block_in_overlap(current: u128, end: u128) -> u8 {
86 let tz = current.trailing_zeros() as u128;
87 let span = (end - current + 1).ilog2_128();
88 let max_block = tz.min(span);
89 (128 - max_block) as u8
90}
91
92fn ipv6_to_u128(addr: Ipv6Addr) -> u128 {
94 u128::from_be_bytes(addr.octets())
95}
96
97trait ILog2U128 {
99 fn ilog2_128(self) -> u128;
100}
101impl ILog2U128 for u128 {
102 fn ilog2_128(self) -> u128 {
103 if self == 0 {
104 0
105 } else {
106 127 - self.leading_zeros() as u128
107 }
108 }
109}