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