ip_in_subnet/lib.rs
1//! # ip-in-subnet
2//!
3//! Checking that subnet contains an IP address.
4//!
5//! ## Usage
6//!
7//! To use `ip-in-subnet`, first add this to your `Cargo.toml`:
8//!
9//! ```toml
10//! [dependencies]
11//! ip-in-subnet = "0.1"
12//! ```
13//!
14//! ## Examples
15//!
16//! ### Check that subnet contains an interface.
17//!
18//! ```
19//! extern crate ip_in_subnet;
20//!
21//! use ip_in_subnet::iface_in_subnet;
22//!
23//! let res = iface_in_subnet("192.168.182.1", "192.168.182.0/24").unwrap();
24//! assert!(res);
25//! ```
26//!
27//! ```
28//! extern crate ip_in_subnet;
29//!
30//! use ip_in_subnet::iface_in_subnet;
31//!
32//! let res = iface_in_subnet("192.168.183.1", "192.168.182.0/24").unwrap();
33//! assert!(!res);
34//! ```
35//!
36//! ### Check that any subnet contains an interface.
37//!
38//! ```
39//! extern crate ip_in_subnet;
40//!
41//! use ip_in_subnet::iface_in_any_subnet;
42//!
43//! let subnets = vec!["192.168.181.0/24", "192.168.182.0/24"];
44//! let res = iface_in_any_subnet("192.168.182.1", &subnets).unwrap();
45//! assert!(res);
46//! ```
47//!
48//! ```
49//! extern crate ip_in_subnet;
50//!
51//! use ip_in_subnet::iface_in_any_subnet;
52//!
53//! let subnets = vec!["192.168.181.0/24", "192.168.182.0/24"];
54//! let res = iface_in_any_subnet("192.168.183.1", &subnets).unwrap();
55//! assert!(!res);
56//! ```
57//!
58//! ### Check that all subnets contains an interface.
59//!
60//! ```
61//! extern crate ip_in_subnet;
62//!
63//! use ip_in_subnet::iface_in_all_subnets;
64//!
65//! let subnets = vec!["192.168.182.0/24", "192.168.182.1/32"];
66//! let res = iface_in_all_subnets("192.168.182.1", &subnets).unwrap();
67//! assert!(res);
68//! ```
69//!
70//! ```
71//! extern crate ip_in_subnet;
72//!
73//! use ip_in_subnet::iface_in_all_subnets;
74//!
75//! let subnets = vec!["192.168.182.0/24", "192.168.182.2/32"];
76//! let res = iface_in_all_subnets("192.168.182.1", &subnets).unwrap();
77//! assert!(!res);
78//! ```
79//!
80//! ### Check that any subnet contains any interface.
81//!
82//! ```
83//! extern crate ip_in_subnet;
84//!
85//! use ip_in_subnet::any_iface_in_any_subnet;
86//!
87//! let ifaces = vec!["192.168.182.1", "192.168.182.2"];
88//! let subnets = vec!["192.168.181.0/24", "192.168.182.2/32"];
89//! let res = any_iface_in_any_subnet(&ifaces, &subnets).unwrap();
90//! assert!(res);
91//! ```
92//!
93//! ```
94//! extern crate ip_in_subnet;
95//!
96//! use ip_in_subnet::any_iface_in_any_subnet;
97//!
98//! let ifaces = vec!["192.168.182.1", "192.168.182.2"];
99//! let subnets = vec!["192.168.181.0/24", "192.168.182.3/32"];
100//! let res = any_iface_in_any_subnet(&ifaces, &subnets).unwrap();
101//! assert!(!res);
102//! ```
103
104use netaddr2::{Contains, Error as NetError, NetAddr};
105use std::error::Error;
106use std::net::{Ipv4Addr, Ipv6Addr};
107
108/// Check that subnet contains an interface.
109///
110/// # Examples
111///
112/// ```
113/// extern crate ip_in_subnet;
114///
115/// use ip_in_subnet::iface_in_subnet;
116///
117/// let res = iface_in_subnet("192.168.182.1", "192.168.182.0/24").unwrap();
118/// assert!(res);
119/// ```
120///
121/// ```
122/// extern crate ip_in_subnet;
123///
124/// use ip_in_subnet::iface_in_subnet;
125///
126/// let res = iface_in_subnet("192.168.183.1", "192.168.182.0/24").unwrap();
127/// assert!(!res);
128/// ```
129pub fn iface_in_subnet(iface: &str, subnet: &str) -> Result<bool, Box<dyn Error>> {
130 match subnet.parse::<NetAddr>() {
131 Ok(NetAddr::V4(subnet4)) => {
132 if let Ok(iface) = iface.parse::<Ipv4Addr>() {
133 let is_in = subnet4.contains(&iface);
134 Ok(is_in)
135 } else {
136 Ok(false)
137 }
138 }
139 Ok(NetAddr::V6(subnet6)) => {
140 if let Ok(iface) = iface.parse::<Ipv6Addr>() {
141 let is_in = subnet6.contains(&iface);
142 Ok(is_in)
143 } else {
144 Ok(false)
145 }
146 }
147 Err(NetError::ParseError(e)) => Err(e.into()),
148 }
149}
150
151/// Check that any subnet contains an interface.
152///
153/// # Examples
154///
155/// ```
156/// extern crate ip_in_subnet;
157///
158/// use ip_in_subnet::iface_in_any_subnet;
159///
160/// let subnets = vec!["192.168.181.0/24", "192.168.182.0/24"];
161/// let res = iface_in_any_subnet("192.168.182.1", &subnets).unwrap();
162/// assert!(res);
163/// ```
164///
165/// ```
166/// extern crate ip_in_subnet;
167///
168/// use ip_in_subnet::iface_in_any_subnet;
169///
170/// let subnets = vec!["192.168.181.0/24", "192.168.182.0/24"];
171/// let res = iface_in_any_subnet("192.168.183.1", &subnets).unwrap();
172/// assert!(!res);
173/// ```
174pub fn iface_in_any_subnet(iface: &str, subnets: &[&str]) -> Result<bool, Box<dyn Error>> {
175 let mut iface4 = None;
176 let mut iface6 = None;
177 for subnet in subnets.iter() {
178 match subnet.parse::<NetAddr>() {
179 Ok(NetAddr::V4(subnet4)) => {
180 if iface4.is_none() {
181 if let Ok(iface) = iface.parse::<Ipv4Addr>() {
182 iface4 = Some(iface);
183 } else {
184 continue;
185 }
186 }
187 if subnet4.contains(&iface4.unwrap()) {
188 return Ok(true);
189 }
190 }
191 Ok(NetAddr::V6(subnet6)) => {
192 if iface6.is_none() {
193 if let Ok(iface) = iface.parse::<Ipv6Addr>() {
194 iface6 = Some(iface);
195 } else {
196 continue;
197 }
198 }
199 if subnet6.contains(&iface6.unwrap()) {
200 return Ok(true);
201 }
202 }
203 Err(NetError::ParseError(e)) => return Err(e.into()),
204 }
205 }
206 Ok(false)
207}
208
209/// Check that all subnets contains an interface.
210///
211/// # Examples
212///
213/// ```
214/// extern crate ip_in_subnet;
215///
216/// use ip_in_subnet::iface_in_all_subnets;
217///
218/// let subnets = vec!["192.168.182.0/24", "192.168.182.1/32"];
219/// let res = iface_in_all_subnets("192.168.182.1", &subnets).unwrap();
220/// assert!(res);
221/// ```
222///
223/// ```
224/// extern crate ip_in_subnet;
225///
226/// use ip_in_subnet::iface_in_all_subnets;
227///
228/// let subnets = vec!["192.168.182.0/24", "192.168.182.2/32"];
229/// let res = iface_in_all_subnets("192.168.182.1", &subnets).unwrap();
230/// assert!(!res);
231/// ```
232pub fn iface_in_all_subnets(iface: &str, subnets: &[&str]) -> Result<bool, Box<dyn Error>> {
233 for subnet in subnets.iter() {
234 let res = iface_in_subnet(&iface, &subnet);
235 if let Ok(false) = res {
236 return Ok(false);
237 }
238 }
239 Ok(true)
240}
241
242/// Check that any subnet contains any interface.
243///
244/// # Examples
245///
246/// ```
247/// extern crate ip_in_subnet;
248///
249/// use ip_in_subnet::any_iface_in_any_subnet;
250///
251/// let ifaces = vec!["192.168.182.1", "192.168.182.2"];
252/// let subnets = vec!["192.168.181.0/24", "192.168.182.2/32"];
253/// let res = any_iface_in_any_subnet(&ifaces, &subnets).unwrap();
254/// assert!(res);
255/// ```
256///
257/// ```
258/// extern crate ip_in_subnet;
259///
260/// use ip_in_subnet::any_iface_in_any_subnet;
261///
262/// let ifaces = vec!["192.168.182.1", "192.168.182.2"];
263/// let subnets = vec!["192.168.181.0/24", "192.168.182.3/32"];
264/// let res = any_iface_in_any_subnet(&ifaces, &subnets).unwrap();
265/// assert!(!res);
266/// ```
267pub fn any_iface_in_any_subnet(ifaces: &[&str], subnets: &[&str]) -> Result<bool, Box<dyn Error>> {
268 for subnet in subnets.iter() {
269 match subnet.parse::<NetAddr>() {
270 Ok(NetAddr::V4(subnet4)) => {
271 for iface in ifaces.iter() {
272 if let Ok(iface) = iface.parse::<Ipv4Addr>() {
273 if subnet4.contains(&iface) {
274 return Ok(true)
275 }
276 }
277 }
278 }
279 Ok(NetAddr::V6(subnet6)) => {
280 for iface in ifaces.iter() {
281 if let Ok(iface) = iface.parse::<Ipv6Addr>() {
282 if subnet6.contains(&iface) {
283 return Ok(true)
284 }
285 }
286 }
287 }
288 Err(NetError::ParseError(e)) => return Err(e.into()),
289 }
290 }
291 Ok(false)
292}
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297
298 #[test]
299 fn test_iface_in_subnet() {
300 let res = iface_in_subnet("192.168.182.1", "192.168.182.0/24").unwrap();
301 assert!(res);
302 }
303
304 #[test]
305 fn test_iface_not_in_subnet() {
306 let res = iface_in_subnet("192.168.183.1", "192.168.182.0/24").unwrap();
307 assert!(!res);
308 }
309
310 #[test]
311 fn test_iface_in_any_subnet() {
312 let subnets = vec!["192.168.181.0/24", "192.168.182.0/24"];
313 let res = iface_in_any_subnet("192.168.182.1", &subnets).unwrap();
314 assert!(res);
315 }
316
317 #[test]
318 fn test_iface_not_in_any_subnet() {
319 let subnets = vec!["192.168.181.0/24", "192.168.182.0/24"];
320 let res = iface_in_any_subnet("192.168.183.1", &subnets).unwrap();
321 assert!(!res);
322 }
323
324 #[test]
325 fn test_iface_in_all_subnets() {
326 let subnets = vec!["192.168.182.0/24", "192.168.182.1/32"];
327 let res = iface_in_all_subnets("192.168.182.1", &subnets).unwrap();
328 assert!(res);
329 }
330
331 #[test]
332 fn test_iface_not_in_all_subnets() {
333 let subnets = vec!["192.168.182.0/24", "192.168.182.2/32"];
334 let res = iface_in_all_subnets("192.168.182.1", &subnets).unwrap();
335 assert!(!res);
336 }
337
338 #[test]
339 fn test_any_iface_in_any_subnet() {
340 let ifaces = vec!["192.168.182.1", "192.168.182.2"];
341 let subnets = vec!["192.168.181.0/24", "192.168.182.2/32"];
342 let res = any_iface_in_any_subnet(&ifaces, &subnets).unwrap();
343 assert!(res);
344 }
345
346 #[test]
347 fn test_any_iface_not_in_any_subnet() {
348 let ifaces = vec!["192.168.182.1", "192.168.182.2"];
349 let subnets = vec!["192.168.181.0/24", "192.168.182.3/32"];
350 let res = any_iface_in_any_subnet(&ifaces, &subnets).unwrap();
351 assert!(!res);
352 }
353}