ipnetwork/
lib.rs

1//! The `ipnetwork` crate provides a set of APIs to work with IP CIDRs in
2//! Rust.
3#![crate_type = "lib"]
4#![deny(
5    missing_debug_implementations,
6    unsafe_code,
7    unused_extern_crates,
8    unused_import_braces
9)]
10
11use std::{convert::TryFrom, fmt, net::IpAddr, str::FromStr};
12
13mod error;
14mod ipv4;
15mod ipv6;
16mod parse;
17mod size;
18
19pub use crate::error::{NetworkSizeError, IpNetworkError};
20pub use crate::ipv4::Ipv4NetworkIterator;
21pub use crate::ipv4::{ipv4_mask_to_prefix, Ipv4Network};
22pub use crate::ipv6::Ipv6NetworkIterator;
23pub use crate::ipv6::{ipv6_mask_to_prefix, Ipv6Network};
24pub use crate::size::NetworkSize;
25
26/// Represents a generic network range. This type can have two variants:
27/// the v4 and the v6 case.
28#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
29pub enum IpNetwork {
30    V4(Ipv4Network),
31    V6(Ipv6Network),
32}
33
34#[cfg(feature = "serde")]
35impl<'de> serde::Deserialize<'de> for IpNetwork {
36    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
37    where
38        D: serde::Deserializer<'de>,
39    {
40        let s = <String>::deserialize(deserializer)?;
41        IpNetwork::from_str(&s).map_err(serde::de::Error::custom)
42    }
43}
44
45#[cfg(feature = "serde")]
46impl serde::Serialize for IpNetwork {
47    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
48    where
49        S: serde::Serializer,
50    {
51        serializer.collect_str(self)
52    }
53}
54
55#[cfg(feature = "schemars")]
56impl schemars::JsonSchema for IpNetwork {
57    fn schema_name() -> String {
58        "IpNetwork".to_string()
59    }
60
61    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
62        schemars::schema::SchemaObject {
63            metadata: Some(
64                schemars::schema::Metadata {
65                    ..Default::default()
66                }
67                .into(),
68            ),
69            subschemas: Some(
70                schemars::schema::SubschemaValidation {
71                    one_of: Some(vec![
72                        schemars::schema::SchemaObject {
73                            metadata: Some(
74                                schemars::schema::Metadata {
75                                    title: Some("v4".to_string()),
76                                    ..Default::default()
77                                }
78                                .into(),
79                            ),
80                            subschemas: Some(
81                                schemars::schema::SubschemaValidation {
82                                    all_of: Some(vec![gen.subschema_for::<Ipv4Network>()]),
83                                    ..Default::default()
84                                }
85                                .into(),
86                            ),
87                            ..Default::default()
88                        }
89                        .into(),
90                        schemars::schema::SchemaObject {
91                            metadata: Some(
92                                schemars::schema::Metadata {
93                                    title: Some("v6".to_string()),
94                                    ..Default::default()
95                                }
96                                .into(),
97                            ),
98                            subschemas: Some(
99                                schemars::schema::SubschemaValidation {
100                                    all_of: Some(vec![gen.subschema_for::<Ipv6Network>()]),
101                                    ..Default::default()
102                                }
103                                .into(),
104                            ),
105                            ..Default::default()
106                        }
107                        .into(),
108                    ]),
109                    ..Default::default()
110                }
111                .into(),
112            ),
113            extensions: [("x-rust-type".to_string(), "ipnetwork::IpNetwork".into())]
114                .iter()
115                .cloned()
116                .collect(),
117            ..Default::default()
118        }
119        .into()
120    }
121}
122
123impl IpNetwork {
124    /// Constructs a new `IpNetwork` from a given `IpAddr` and a prefix denoting the
125    /// network size. If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
126    /// will raise an `IpNetworkError::InvalidPrefix` error. Support for IPv6 is not
127    /// complete yet.
128    pub fn new(ip: IpAddr, prefix: u8) -> Result<IpNetwork, IpNetworkError> {
129        match ip {
130            IpAddr::V4(a) => Ok(IpNetwork::V4(Ipv4Network::new(a, prefix)?)),
131            IpAddr::V6(a) => Ok(IpNetwork::V6(Ipv6Network::new(a, prefix)?)),
132        }
133    }
134
135    /// Constructs a new `IpNetwork` from a network address and a network mask.
136    ///
137    /// If the netmask is not valid this will return an `IpNetworkError::InvalidPrefix`.
138    pub fn with_netmask(netaddr: IpAddr, netmask: IpAddr) -> Result<Self, IpNetworkError> {
139        let prefix = ip_mask_to_prefix(netmask)?;
140        Self::new(netaddr, prefix)
141    }
142
143    /// Returns the IP part of a given `IpNetwork`
144    pub fn ip(&self) -> IpAddr {
145        match *self {
146            IpNetwork::V4(ref a) => IpAddr::V4(a.ip()),
147            IpNetwork::V6(ref a) => IpAddr::V6(a.ip()),
148        }
149    }
150
151    /// Returns the prefix of the given `IpNetwork`
152    ///
153    /// # Example
154    /// ```
155    /// use ipnetwork::IpNetwork;
156    ///
157    /// assert_eq!(IpNetwork::V4("10.9.0.1".parse().unwrap()).prefix(), 32u8);
158    /// assert_eq!(IpNetwork::V4("10.9.0.32/16".parse().unwrap()).prefix(), 16u8);
159    ///
160    /// assert_eq!(IpNetwork::V6("ff01::0".parse().unwrap()).prefix(), 128u8);
161    /// assert_eq!(IpNetwork::V6("ff01::0/32".parse().unwrap()).prefix(), 32u8);
162    /// ```
163    pub fn prefix(&self) -> u8 {
164        match *self {
165            IpNetwork::V4(ref a) => a.prefix(),
166            IpNetwork::V6(ref a) => a.prefix(),
167        }
168    }
169
170    /// Returns the address of the network denoted by this `IpNetwork`.
171    /// This means the lowest possible IP address inside of the network.
172    ///
173    /// # Examples
174    ///
175    /// ```
176    /// use std::net::{Ipv4Addr, Ipv6Addr};
177    /// use ipnetwork::IpNetwork;
178    ///
179    /// let net: IpNetwork = "10.1.9.32/16".parse().unwrap();
180    /// assert_eq!(net.network(), Ipv4Addr::new(10, 1, 0, 0));
181    /// let net: IpNetwork = "2001:db8::/96".parse().unwrap();
182    /// assert_eq!(net.network(), Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0));
183    /// ```
184    pub fn network(&self) -> IpAddr {
185        match *self {
186            IpNetwork::V4(ref a) => IpAddr::V4(a.network()),
187            IpNetwork::V6(ref a) => IpAddr::V6(a.network()),
188        }
189    }
190
191    /// Returns the broadcasting address of this `IpNetwork`.
192    /// This means the highest possible IP address inside of the network.
193    ///
194    /// # Examples
195    ///
196    /// ```
197    /// use std::net::Ipv4Addr;
198    /// use ipnetwork::{IpNetwork, Ipv4Network};
199    ///
200    /// let net: Ipv4Network = "10.9.0.32/16".parse().unwrap();
201    /// assert_eq!(net.broadcast(), Ipv4Addr::new(10, 9, 255, 255));
202    /// ```
203    pub fn broadcast(&self) -> IpAddr {
204        match *self {
205            IpNetwork::V4(ref a) => IpAddr::V4(a.broadcast()),
206            IpNetwork::V6(ref a) => IpAddr::V6(a.broadcast()),
207        }
208    }
209
210    /// Returns the mask for this `IpNetwork`.
211    /// That means the `prefix` most significant bits will be 1 and the rest 0
212    ///
213    /// # Example
214    ///
215    /// ```
216    /// use ipnetwork::IpNetwork;
217    /// use std::net::{Ipv4Addr, Ipv6Addr};
218    ///
219    /// let v4_net: IpNetwork = "10.9.0.1".parse().unwrap();
220    /// assert_eq!(v4_net.mask(), Ipv4Addr::new(255, 255, 255, 255));
221    /// let v4_net: IpNetwork = "10.9.0.32/16".parse().unwrap();
222    /// assert_eq!(v4_net.mask(), Ipv4Addr::new(255, 255, 0, 0));
223    ///
224    /// let v6_net: IpNetwork = "ff01::0".parse().unwrap();
225    /// assert_eq!(v6_net.mask(), Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff));
226    /// let v6_net: IpNetwork = "ff01::0/32".parse().unwrap();
227    /// assert_eq!(v6_net.mask(), Ipv6Addr::new(0xffff, 0xffff, 0, 0, 0, 0, 0, 0));
228    /// ```
229    pub fn mask(&self) -> IpAddr {
230        match *self {
231            IpNetwork::V4(ref a) => IpAddr::V4(a.mask()),
232            IpNetwork::V6(ref a) => IpAddr::V6(a.mask()),
233        }
234    }
235
236    /// Returns true if the IP in this `IpNetwork` is a valid IPv4 address,
237    /// false if it's a valid IPv6 address.
238    ///
239    /// # Example
240    ///
241    ///```
242    /// use ipnetwork::IpNetwork;
243    ///
244    /// let v4: IpNetwork = IpNetwork::V4("10.9.0.32/16".parse().unwrap());
245    /// assert_eq!(v4.is_ipv4(), true);
246    /// assert_eq!(v4.is_ipv6(), false);
247    ///```
248    pub fn is_ipv4(&self) -> bool {
249        match *self {
250            IpNetwork::V4(_) => true,
251            IpNetwork::V6(_) => false,
252        }
253    }
254
255    /// Returns true if the IP in this `IpNetwork` is a valid IPv6 address,
256    /// false if it's a valid IPv4 address.
257    ///
258    /// # Example
259    ///
260    ///```
261    /// use ipnetwork::IpNetwork;
262    ///
263    /// let v6: IpNetwork = IpNetwork::V6("ff01::0/32".parse().unwrap());
264    /// assert_eq!(v6.is_ipv6(), true);
265    /// assert_eq!(v6.is_ipv4(), false);
266    ///```
267    pub fn is_ipv6(&self) -> bool {
268        match *self {
269            IpNetwork::V4(_) => false,
270            IpNetwork::V6(_) => true,
271        }
272    }
273
274    // TODO(abhishek) when TryFrom is stable, implement it for IpNetwork to
275    // variant conversions. Then use that to implement a generic is_subnet_of
276    // is_supernet_of, overlaps
277
278    /// Checks if a given `IpAddr` is in this `IpNetwork`
279    ///
280    /// # Examples
281    ///
282    /// ```
283    /// use std::net::IpAddr;
284    /// use ipnetwork::IpNetwork;
285    ///
286    /// let net: IpNetwork = "127.0.0.0/24".parse().unwrap();
287    /// let ip1: IpAddr = "127.0.0.1".parse().unwrap();
288    /// let ip2: IpAddr = "172.0.0.1".parse().unwrap();
289    /// let ip4: IpAddr = "::1".parse().unwrap();
290    /// assert!(net.contains(ip1));
291    /// assert!(!net.contains(ip2));
292    /// assert!(!net.contains(ip4));
293    /// ```
294    #[inline]
295    pub fn contains(&self, ip: IpAddr) -> bool {
296        match (*self, ip) {
297            (IpNetwork::V4(net), IpAddr::V4(ip)) => net.contains(ip),
298            (IpNetwork::V6(net), IpAddr::V6(ip)) => net.contains(ip),
299            _ => false,
300        }
301    }
302
303    /// Returns the number of possible host addresses in this `IpAddr`
304    ///
305    /// # Examples
306    ///
307    /// ```
308    /// use ipnetwork::{IpNetwork, NetworkSize};
309    ///
310    ///
311    /// let net: IpNetwork = "127.0.0.0/24".parse().unwrap();
312    /// assert_eq!(net.size(), NetworkSize::V4(256))
313    /// ```
314    pub fn size(&self) -> NetworkSize {
315        match *self {
316            IpNetwork::V4(ref ip) => NetworkSize::V4(ip.size()),
317            IpNetwork::V6(ref ip) => NetworkSize::V6(ip.size()),
318        }
319    }
320
321    /// Returns an iterator over the addresses contained in the network.
322    ///
323    /// This lists all the addresses in the network range, in ascending order.
324    pub fn iter(&self) -> IpNetworkIterator {
325        let inner = match self {
326            IpNetwork::V4(ip) => IpNetworkIteratorInner::V4(ip.iter()),
327            IpNetwork::V6(ip) => IpNetworkIteratorInner::V6(ip.iter()),
328        };
329        IpNetworkIterator { inner }
330    }
331}
332
333/// Tries to parse the given string into a `IpNetwork`. Will first try to parse
334/// it as an `Ipv4Network` and if that fails as an `Ipv6Network`. If both
335/// fails it will return an `InvalidAddr` error.
336///
337/// # Examples
338///
339/// ```
340/// use std::net::Ipv4Addr;
341/// use ipnetwork::{IpNetwork, Ipv4Network};
342///
343/// let expected = IpNetwork::V4(Ipv4Network::new(Ipv4Addr::new(10, 1, 9, 32), 16).unwrap());
344/// let from_cidr: IpNetwork = "10.1.9.32/16".parse().unwrap();
345/// assert_eq!(expected, from_cidr);
346/// ```
347impl FromStr for IpNetwork {
348    type Err = IpNetworkError;
349    fn from_str(s: &str) -> Result<Self, Self::Err> {
350        if let Ok(net) = Ipv4Network::from_str(s) {
351            Ok(IpNetwork::V4(net))
352        } else if let Ok(net) = Ipv6Network::from_str(s) {
353            Ok(IpNetwork::V6(net))
354        } else {
355            Err(IpNetworkError::InvalidAddr(s.to_string()))
356        }
357    }
358}
359
360impl TryFrom<&str> for IpNetwork {
361    type Error = IpNetworkError;
362
363    fn try_from(s: &str) -> Result<Self, Self::Error> {
364        IpNetwork::from_str(s)
365    }
366}
367
368impl From<Ipv4Network> for IpNetwork {
369    fn from(v4: Ipv4Network) -> IpNetwork {
370        IpNetwork::V4(v4)
371    }
372}
373
374impl From<Ipv6Network> for IpNetwork {
375    fn from(v6: Ipv6Network) -> IpNetwork {
376        IpNetwork::V6(v6)
377    }
378}
379
380impl From<IpAddr> for IpNetwork {
381    fn from(addr: IpAddr) -> IpNetwork {
382        match addr {
383            IpAddr::V4(a) => IpNetwork::V4(Ipv4Network::from(a)),
384            IpAddr::V6(a) => IpNetwork::V6(Ipv6Network::from(a)),
385        }
386    }
387}
388
389impl fmt::Display for IpNetwork {
390    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391        match *self {
392            IpNetwork::V4(net) => net.fmt(f),
393            IpNetwork::V6(net) => net.fmt(f),
394        }
395    }
396}
397
398#[derive(Clone, Debug)]
399enum IpNetworkIteratorInner {
400    V4(Ipv4NetworkIterator),
401    V6(Ipv6NetworkIterator),
402}
403
404#[derive(Clone, Debug)]
405pub struct IpNetworkIterator {
406    inner: IpNetworkIteratorInner,
407}
408
409impl Iterator for IpNetworkIterator {
410    type Item = IpAddr;
411    fn next(&mut self) -> Option<IpAddr> {
412        match &mut self.inner {
413            IpNetworkIteratorInner::V4(iter) => iter.next().map(IpAddr::V4),
414            IpNetworkIteratorInner::V6(iter) => iter.next().map(IpAddr::V6),
415        }
416    }
417}
418
419impl IntoIterator for &'_ IpNetwork {
420    type IntoIter = IpNetworkIterator;
421    type Item = IpAddr;
422    fn into_iter(self) -> IpNetworkIterator {
423        self.iter()
424    }
425}
426
427/// Converts a `IpAddr` network mask into a prefix.
428/// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`.
429pub fn ip_mask_to_prefix(mask: IpAddr) -> Result<u8, IpNetworkError> {
430    match mask {
431        IpAddr::V4(mask) => ipv4_mask_to_prefix(mask),
432        IpAddr::V6(mask) => ipv6_mask_to_prefix(mask),
433    }
434}
435
436#[cfg(test)]
437mod test {
438    #[test]
439    #[cfg(feature = "serde")]
440    fn deserialize_from_serde_json_value() {
441        use super::*;
442        let network = IpNetwork::from_str("0.0.0.0/0").unwrap();
443        let val: serde_json::value::Value =
444            serde_json::from_str(&serde_json::to_string(&network).unwrap()).unwrap();
445        let _deser: IpNetwork = serde_json::from_value(val)
446            .expect("Fails to deserialize from json_value::value::Value");
447    }
448}