Skip to main content

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}