netsim_embed_core/
range.rs1use crate::addr::{Ipv4AddrClass, Ipv4AddrExt};
2use std::net::Ipv4Addr;
3use std::str::FromStr;
4use thiserror::Error;
5
6#[derive(Clone, Copy, PartialEq, Eq)]
8pub struct Ipv4Range {
9 addr: Ipv4Addr,
10 bits: u8,
11}
12
13impl std::fmt::Debug for Ipv4Range {
14 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
15 write!(f, "{}/{}", self.addr, self.bits)
16 }
17}
18
19impl Ipv4Range {
20 pub fn new(addr: Ipv4Addr, bits: u8) -> Self {
26 let mask = !((!0u32).checked_shr(u32::from(bits)).unwrap_or(0));
27 Ipv4Range {
28 addr: Ipv4Addr::from(u32::from(addr) & mask),
29 bits,
30 }
31 }
32
33 pub fn global() -> Self {
35 Ipv4Range {
36 addr: Ipv4Addr::new(0, 0, 0, 0),
37 bits: 0,
38 }
39 }
40
41 pub fn local_subnet_10() -> Self {
43 Ipv4Range {
44 addr: Ipv4Addr::new(10, 0, 0, 0),
45 bits: 8,
46 }
47 }
48
49 pub fn local_subnet_172(block: u8) -> Self {
56 assert!(block < 16);
57 Ipv4Range {
58 addr: Ipv4Addr::new(172, 16 | block, 0, 0),
59 bits: 16,
60 }
61 }
62
63 pub fn local_subnet_192(block: u8) -> Self {
65 Ipv4Range {
66 addr: Ipv4Addr::new(192, 168, block, 0),
67 bits: 24,
68 }
69 }
70
71 pub fn random_local_subnet() -> Self {
74 match rand::random::<u8>() % 3 {
75 0 => Ipv4Range::local_subnet_10(),
76 1 => Ipv4Range::local_subnet_172(rand::random::<u8>() & 0x0f),
77 2 => Ipv4Range::local_subnet_192(rand::random()),
78 _ => unreachable!(),
79 }
80 }
81
82 pub fn netmask(&self) -> Ipv4Addr {
84 Ipv4Addr::from(!((!0u32).checked_shr(u32::from(self.bits)).unwrap_or(0)))
85 }
86
87 pub fn netmask_prefix_length(&self) -> u8 {
89 self.bits
90 }
91
92 pub fn base_addr(&self) -> Ipv4Addr {
94 self.addr
95 }
96
97 pub fn gateway_addr(&self) -> Ipv4Addr {
100 Ipv4Addr::from(u32::from(self.addr) | 1)
101 }
102
103 pub fn broadcast_addr(&self) -> Ipv4Addr {
105 Ipv4Addr::from(!(!0 >> self.bits) | u32::from(self.addr))
106 }
107
108 pub fn random_client_addr(&self) -> Ipv4Addr {
111 let mask = !0 >> self.bits;
112 assert!(mask > 1);
113 let class = if self.bits == 0 {
114 Ipv4AddrClass::Global
115 } else {
116 self.addr.class()
117 };
118
119 loop {
120 let x = rand::random::<u32>() & mask;
121 if x < 2 {
122 continue;
123 }
124 let addr = Ipv4Addr::from(u32::from(self.addr) | x);
125 if class != addr.class() {
126 continue;
127 }
128 return addr;
129 }
130 }
131
132 pub fn address_for(&self, device: u32) -> Ipv4Addr {
134 let mask = !0 >> self.bits;
135 assert!(mask > 1);
136 let addr = Ipv4Addr::from(u32::from(self.addr) | ((device & mask) + 2));
137 assert_ne!(addr, self.broadcast_addr());
138 addr
139 }
140
141 pub fn contains(&self, ip: Ipv4Addr) -> bool {
143 let base_addr = u32::from(self.addr);
144 let test_addr = u32::from(ip);
145 (base_addr ^ test_addr).leading_zeros() >= u32::from(self.bits)
146 }
147
148 pub fn split(self, num: u32) -> Vec<Self> {
154 let mut ret = Vec::with_capacity(num as usize);
155 let mut n = 0u32;
156 let class = if self.bits == 0 {
157 Ipv4AddrClass::Global
158 } else {
159 self.addr.class()
160 };
161 loop {
162 let mut n_reversed = 0;
163 for i in 0..32 {
164 if n & (1 << i) != 0 {
165 n_reversed |= 0x8000_0000u32 >> i;
166 }
167 }
168 let base_addr = u32::from(self.addr);
169 let ip = base_addr | (n_reversed >> self.bits);
170 let ip = Ipv4Addr::from(ip);
171 if class != ip.class() {
172 n += 1;
173 continue;
174 }
175 ret.push(Ipv4Range { addr: ip, bits: 0 });
176 if ret.len() == num as usize {
177 break;
178 }
179 n += 1;
180 }
181 let extra_bits = (32 - n.leading_zeros()) as u8;
182 let bits = self.bits + extra_bits;
183 for range in &mut ret {
184 range.bits = bits;
185 }
186 ret
187 }
188}
189
190#[derive(Debug, Error)]
192pub enum IpRangeParseError {
193 #[error("missing '/' delimiter")]
195 MissingDelimiter,
196 #[error("more than one '/' delimiter")]
198 ExtraDelimiter,
199 #[error("error parsing IP address: {0}")]
201 ParseAddr(std::net::AddrParseError),
202 #[error("error parsing netmask prefix length: {0}")]
204 ParseNetmaskPrefixLength(std::num::ParseIntError),
205}
206
207impl FromStr for Ipv4Range {
208 type Err = IpRangeParseError;
209
210 fn from_str(s: &str) -> Result<Ipv4Range, IpRangeParseError> {
211 let mut split = s.split('/');
212 let addr = split.next().unwrap();
213 let bits = match split.next() {
214 Some(bits) => bits,
215 None => return Err(IpRangeParseError::MissingDelimiter),
216 };
217 if split.next().is_some() {
218 return Err(IpRangeParseError::ExtraDelimiter);
219 }
220 let addr = match Ipv4Addr::from_str(addr) {
221 Ok(addr) => addr,
222 Err(e) => return Err(IpRangeParseError::ParseAddr(e)),
223 };
224 let bits = match u8::from_str(bits) {
225 Ok(bits) => bits,
226 Err(e) => return Err(IpRangeParseError::ParseNetmaskPrefixLength(e)),
227 };
228 Ok(Ipv4Range::new(addr, bits))
229 }
230}
231
232impl From<Ipv4Addr> for Ipv4Range {
233 fn from(addr: Ipv4Addr) -> Self {
234 Self::new(addr, 32)
235 }
236}
237
238#[cfg(test)]
239mod tests {
240 use super::*;
241
242 #[test]
243 fn it_creates_address_range() {
244 let addrs = Ipv4Range::new("1.2.3.0".parse().unwrap(), 24);
245
246 assert!(addrs.contains("1.2.3.5".parse().unwrap()));
247 assert!(addrs.contains("1.2.3.255".parse().unwrap()));
248 assert!(!addrs.contains("1.2.4.5".parse().unwrap()));
249 }
250}