1use crate::parse_ipv4::largest_ipv4_block;
2use ipnet::{IpNet, Ipv4Net, Ipv6Net};
3use std::net::Ipv4Addr;
4
5pub fn parse_ip_lines(
8 text: &str,
9 country_code: &str,
10) -> Result<(Vec<IpNet>, Vec<IpNet>), Box<dyn std::error::Error + Send + Sync>> {
11 let mut ipv4_list = Vec::new();
12 let mut ipv6_list = Vec::new();
13
14 for line in text.lines() {
15 if line.starts_with('#') || line.contains('*') || line.contains("reserved") {
17 continue;
18 }
19
20 let params: Vec<&str> = line.split('|').collect();
21 if params.len() < 5 {
22 continue;
23 }
24
25 if params[1] != country_code {
27 continue;
28 }
29
30 let ip_type = params[2];
31 match ip_type {
32 "ipv4" | "ipv6" => match parse_ip_params(¶ms) {
33 Ok(nets) => {
34 if ip_type == "ipv4" {
35 ipv4_list.extend(nets);
36 } else {
37 ipv6_list.extend(nets);
38 }
39 }
40 Err(e) => {
41 eprintln!("[parse_ip_lines] parse_ip_params error: {}", e);
42 }
43 },
44 _ => continue,
45 }
46 }
47
48 Ok((ipv4_list, ipv6_list))
49}
50
51fn parse_ip_params(
53 params: &[&str],
54) -> Result<Vec<IpNet>, Box<dyn std::error::Error + Send + Sync>> {
55 let ip_type = params[2];
56 let start_str = params[3];
57 let value_str = params[4];
58
59 match ip_type {
60 "ipv4" => parse_ipv4_range(start_str, value_str),
61 "ipv6" => parse_ipv6_range(start_str, value_str),
62 _ => Ok(vec![]),
63 }
64}
65
66fn parse_ipv4_range(
68 start_str: &str,
69 value_str: &str,
70) -> Result<Vec<IpNet>, Box<dyn std::error::Error + Send + Sync>> {
71 let start_v4 = start_str.parse::<Ipv4Addr>()?;
72 let width = value_str.parse::<u64>()?;
73 let start_num = u32::from(start_v4);
74
75 let end_num = start_num
76 .checked_add(width as u32)
77 .ok_or("IPv4 range is too large")?
78 .checked_sub(1)
79 .ok_or("Calculation error on IPv4 range")?;
80
81 let mut cidrs = Vec::new();
82 let mut current = start_num;
83
84 while current <= end_num {
85 let max_size = largest_ipv4_block(current, end_num);
86 let net = Ipv4Net::new(Ipv4Addr::from(current), max_size)?;
87 cidrs.push(IpNet::V4(net));
88
89 let block_size = 1u32 << (32 - max_size);
90 current = current.saturating_add(block_size);
91 }
92
93 Ok(cidrs)
94}
95
96fn parse_ipv6_range(
98 start_str: &str,
99 value_str: &str,
100) -> Result<Vec<IpNet>, Box<dyn std::error::Error + Send + Sync>> {
101 let cidr_str = format!("{}/{}", start_str, value_str);
103 let net = cidr_str.parse::<Ipv6Net>()?;
104 Ok(vec![IpNet::V6(net)])
105}