Skip to content

Commit 10d7b2d

Browse files
authored
Merge pull request #1 from ugwis/dev
[MASTER MERGE] Structurize IPv4 CIDR
2 parents abfd60e + 7e386d3 commit 10d7b2d

File tree

1 file changed

+113
-84
lines changed

1 file changed

+113
-84
lines changed

src/main.rs

Lines changed: 113 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,128 @@
11
use std::io::{self, BufRead};
2+
use std::fmt::Display;
3+
use std::fmt::Formatter;
4+
use std::net::Ipv4Addr;
5+
use std::net::AddrParseError;
6+
use std::str::FromStr;
7+
use std::num::ParseIntError;
28

9+
enum MyError {
10+
ParseIntError(ParseIntError),
11+
ParseIpv4Error(AddrParseError),
12+
}
313

4-
fn ipv4todec(ipv4: String) -> u32 {
5-
let v: Vec<&str> = ipv4.split('.').collect();
6-
let mut sum: u32 = 0;
7-
for x in v {
8-
sum = sum*256 + x.parse::<u32>().unwrap();
14+
impl Display for MyError {
15+
fn fmt(&self, _: &mut Formatter) -> std::fmt::Result {
16+
match *self {
17+
MyError::ParseIntError(ref e) => print!("Parse int error {}",e),
18+
MyError::ParseIpv4Error(ref e) => print!("Parse Ipv4 address error {}",e)
19+
}
20+
Ok(())
921
}
10-
return sum;
1122
}
1223

13-
fn dectoipv4(mut dec: u32) -> String {
14-
let mut ret: String = "".to_string();
15-
for i in 0..4 {
16-
if i > 0 {
17-
ret = ".".to_string() + &ret;
18-
}
19-
ret = (dec % 256).to_string() + &ret;
20-
dec /= 256;
24+
impl std::convert::From<ParseIntError> for MyError {
25+
fn from(e: ParseIntError) -> Self {
26+
MyError::ParseIntError(e)
2127
}
22-
return ret;
2328
}
2429

25-
// Calculate Network address from CIDR block
26-
fn calc_network_addr(cidr: String) -> String {
27-
let v: Vec<&str> = cidr.split('/').collect();
28-
let net = v[0].to_string();
29-
let mask = v[1].parse::<u32>().unwrap();
30-
let mask_num = 2_u32.pow(32 - mask);
31-
let network_address_num = ipv4todec(net)/mask_num * mask_num;
32-
return dectoipv4(network_address_num);
30+
impl std::convert::From<AddrParseError> for MyError {
31+
fn from(e: AddrParseError) -> Self {
32+
MyError::ParseIpv4Error(e)
33+
}
3334
}
3435

35-
// Calculate Broadcast address from CIDR block
36-
fn calc_broadcast_addr(cidr: String) -> String {
37-
let v: Vec<&str> = cidr.split('/').collect();
38-
let net = v[0].to_string();
39-
let mask = v[1].parse::<u32>().unwrap();
40-
let mask_num = 2_u32.pow(32 - mask);
41-
let network_address_num = (1 + ipv4todec(net)/mask_num) * mask_num - 1;
42-
return dectoipv4(network_address_num);
36+
37+
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
38+
struct Ipv4Cidr {
39+
address: Ipv4Addr,
40+
mask: u8,
4341
}
4442

45-
// Calculate Network mask from CIDR block
46-
fn calc_network_mask(cidr: String) -> u32 {
47-
let v: Vec<&str> = cidr.split('/').collect();
48-
let mask = v[1].parse::<u32>().unwrap();
49-
return mask;
43+
impl Ipv4Cidr {
44+
fn new(address: Ipv4Addr, mask: u8) -> Self {
45+
let cidr = Ipv4Cidr { address, mask };
46+
return Self {
47+
address: cidr.network_addr(),
48+
mask: cidr.network_mask(),
49+
}
50+
}
51+
fn to_string(&self) -> String {
52+
format!("{}/{}", self.address, self.mask)
53+
}
54+
fn mask_filter(&self) -> u32 {
55+
(!0u32).checked_shr(self.mask as u32).unwrap_or(0)
56+
}
57+
fn network_addr(&self) -> Ipv4Addr {
58+
Ipv4Addr::from(u32::from(self.address) & !self.mask_filter())
59+
}
60+
fn broadcast_addr(&self) -> Ipv4Addr {
61+
Ipv4Addr::from(u32::from(self.address) | self.mask_filter())
62+
}
63+
fn network_mask(&self) -> u8 {
64+
self.mask
65+
}
66+
fn generate_wrap_cidr(&self) -> Ipv4Cidr {
67+
Ipv4Cidr::new(
68+
self.address,
69+
self.mask - 1
70+
)
71+
}
5072
}
5173

52-
// Generate CIDR from Network address and mask
53-
fn gen_cidr(network: String, mask: u32) -> String {
54-
return network + "/" + &mask.to_string()
74+
impl FromStr for Ipv4Cidr {
75+
type Err = MyError;
76+
fn from_str(cidr: &str) -> Result<Self, Self::Err> {
77+
let v: Vec<&str> = cidr.split('/').collect();
78+
Ok(Ipv4Cidr::new(
79+
Ipv4Addr::from_str(v[0]).unwrap(),
80+
v[1].parse::<u8>()?
81+
))
82+
}
5583
}
5684

57-
// Merge two CIDR blocks
58-
fn merge(cidr1: String, cidr2: String) -> Vec<String> {
59-
let cidr1_net = ipv4todec(calc_network_addr(cidr1.clone()));
60-
let cidr2_net = ipv4todec(calc_network_addr(cidr2.clone()));
61-
let cidr1_brd = ipv4todec(calc_broadcast_addr(cidr1.clone()));
62-
let cidr2_brd = ipv4todec(calc_broadcast_addr(cidr2.clone()));
63-
let cidr1_mask = calc_network_mask(cidr1.clone());
64-
let cidr2_mask = calc_network_mask(cidr2.clone());
6585

66-
//inclusion
67-
if cidr1_net <= cidr2_net && cidr2_brd <= cidr1_brd {
68-
return vec![cidr1];
86+
// Merge two CIDR blocks
87+
fn merge(cidr1: Ipv4Cidr, cidr2: Ipv4Cidr) -> Option<Ipv4Cidr> {
88+
// Check wether cidr1 includes cidr2 vice versa
89+
if cidr1.network_addr() <= cidr2.network_addr() && cidr2.broadcast_addr() <= cidr1.broadcast_addr() {
90+
return Some(cidr1);
6991
}
70-
if cidr2_net <= cidr1_net && cidr1_brd <= cidr2_brd {
71-
return vec![cidr2];
92+
if cidr2.network_addr() <= cidr1.network_addr() && cidr1.broadcast_addr() <= cidr2.broadcast_addr() {
93+
return Some(cidr2);
7294
}
7395

74-
//adjascent
75-
let cidr1_wrap_net = ipv4todec(calc_network_addr(gen_cidr(dectoipv4(cidr1_net), cidr1_mask - 1)));
76-
let cidr2_wrap_brd = ipv4todec(calc_broadcast_addr(gen_cidr(dectoipv4(cidr2_net), cidr2_mask - 1)));
77-
if cidr1_wrap_net == cidr1_net && cidr1_brd + 1 == cidr2_net && cidr2_wrap_brd == cidr2_brd {
78-
return vec![gen_cidr(dectoipv4(cidr1_net), cidr1_mask - 1)];
96+
// Check wether cidr1 is adjascent to cidr2 vice versa
97+
let cidr3 = cidr1.generate_wrap_cidr();
98+
let cidr4 = cidr2.generate_wrap_cidr();
99+
//println!("[{}-{}]{} == {}: {}", cidr1.to_string(), cidr2.to_string(), cidr3.to_string(), cidr4.to_string(), cidr3==cidr4);
100+
if cidr3 == cidr4 && cidr1 != cidr2 {
101+
return Some(cidr3);
79102
}
80-
return vec![cidr1, cidr2];
103+
return None;
81104
}
82105

83-
// Check wether two CIDR blocks are adjascent
84-
fn is_adjascent(cidr1: String, cidr2: String) -> bool {
85-
let cidr2_net = ipv4todec(calc_network_addr(cidr2.clone()));
86-
let cidr1_brd = ipv4todec(calc_broadcast_addr(cidr1.clone()));
87-
return cidr1_brd + 1 == cidr2_net;
106+
// Check wether two CIDR blocks are not mergable but adjascent
107+
fn is_adjascent(cidr1: Ipv4Cidr, cidr2: Ipv4Cidr) -> bool {
108+
return u32::from(cidr1.broadcast_addr()) + 1 == u32::from(cidr2.network_addr());
88109
}
89110

111+
90112
fn main() {
91113
let stdin = io::stdin();
92114
let mut cidrs = Vec::new();
93115
for line in stdin.lock().lines() {
94-
//println!("{}", dectoipv4(ipv4todec(line.unwrap())+1));
95-
cidrs.push(line.unwrap());
116+
let line = line.unwrap();
117+
let line = line.as_str().trim();
118+
if line.is_empty() || line.starts_with('#') {
119+
continue;
120+
}
121+
let cidr = match Ipv4Cidr::from_str(line) {
122+
Ok(cidr) => cidr,
123+
Err(e) => panic!("Failed to parse {:?} as CIDR: {}", line, e),
124+
};
125+
cidrs.push(cidr);
96126
}
97127
//cidrs.sort();
98128
/*cidrs.sort_by(|a, b| {
@@ -103,29 +133,28 @@ fn main() {
103133
stack.push(cidr);
104134
//println!("{:?}", stack);
105135
while stack.len() >= 2 {
106-
let m2 = stack.pop().unwrap();
107-
let m1 = stack.pop().unwrap();
108-
let merged = merge(m1.clone(), m2.clone());
109-
if merged.len() == 1 {
110-
//mergeable
111-
stack.push(merged[0].clone());
112-
} else {
113-
stack.push(merged[0].clone());
114-
if ! is_adjascent(m1.clone(), m2.clone()) {
115-
for x in stack {
116-
println!("{}", x);
136+
let cidr2 = stack.pop().unwrap();
137+
let cidr1 = stack.pop().unwrap();
138+
let merged = merge(cidr1, cidr2);
139+
match merged {
140+
Some(merged) => {
141+
stack.push(merged);
142+
},
143+
None => {
144+
stack.push(cidr1);
145+
if ! is_adjascent(cidr1, cidr2) {
146+
for x in stack {
147+
println!("{}", x.to_string());
148+
}
149+
stack = Vec::new();
117150
}
118-
stack = Vec::new();
119-
}
120-
stack.push(merged[1].clone());
121-
break;
151+
stack.push(cidr2);
152+
break;
153+
},
122154
}
123155
}
124156
}
125157
for x in stack {
126-
println!("{}", x);
158+
println!("{}", x.to_string());
127159
}
128-
/*let args: Vec<String> = env::args().collect();
129-
let dec = dectoipv4(ipv4todec(&args[1]));
130-
println!("{}", dec);*/
131160
}

0 commit comments

Comments
 (0)