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