cidr/cidr/
any.rs

1use core::{
2	fmt,
3	net::{
4		IpAddr,
5		Ipv4Addr,
6		Ipv6Addr,
7	},
8	str::FromStr,
9};
10
11use crate::{
12	errors::*,
13	Family,
14	IpCidr,
15	IpInet,
16	Ipv4Cidr,
17	Ipv6Cidr,
18};
19
20/// Represents either an IPv4 or an IPv6 network or "any".
21///
22/// Allows for a bit string representation which treats "any" as the
23/// empty string, IPv4 as starting with `false` and IPv6 as starting
24/// with `true`. After the first bit the normal represenation for the
25/// picked address-family follows.
26///
27/// Setting the first bit (using the `bitstring` API) always truncates
28/// the bit string to length 1 (i.e. `/0` in the resulting family).
29///
30/// The [`Cidr`] trait cannot be implemented for this type.
31///
32/// [`Cidr`]: crate::Cidr
33#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
34pub enum AnyIpCidr {
35	/// "any" network containing all IPv4 and IPv6 addresses
36	Any,
37	/// IPv4 network
38	V4(Ipv4Cidr),
39	/// IPv6 network
40	V6(Ipv6Cidr),
41}
42
43impl AnyIpCidr {
44	/// Whether representing any address
45	pub const fn is_any(&self) -> bool {
46		match self {
47			Self::Any => true,
48			_ => false,
49		}
50	}
51
52	/// Whether representing an IPv4 network
53	pub const fn is_ipv4(&self) -> bool {
54		match self {
55			Self::V4(_) => true,
56			_ => false,
57		}
58	}
59
60	/// Whether representing an IPv6 network
61	pub const fn is_ipv6(&self) -> bool {
62		match self {
63			Self::V4(_) => false,
64			_ => true,
65		}
66	}
67}
68
69// "Cidr" functions
70impl AnyIpCidr {
71	/// Create new network from address and prefix length.  If the
72	/// network length exceeds the address length or the address is not
73	/// the first address in the network ("host part not zero") an error
74	/// is returned.
75	pub const fn new(addr: IpAddr, len: u8) -> Result<Self, NetworkParseError> {
76		match addr {
77			IpAddr::V4(a) => match Ipv4Cidr::new(a, len) {
78				Ok(cidr) => Ok(Self::V4(cidr)),
79				Err(e) => Err(e),
80			},
81			IpAddr::V6(a) => match Ipv6Cidr::new(a, len) {
82				Ok(cidr) => Ok(Self::V6(cidr)),
83				Err(e) => Err(e),
84			},
85		}
86	}
87
88	/// Create a network containing a single address (network length =
89	/// address length).
90	pub const fn new_host(addr: IpAddr) -> Self {
91		match addr {
92			IpAddr::V4(a) => Self::V4(Ipv4Cidr::new_host(a)),
93			IpAddr::V6(a) => Self::V6(Ipv6Cidr::new_host(a)),
94		}
95	}
96
97	/// first address in the network as plain address
98	///
99	/// returns [`None`] for [`Any`]
100	///
101	/// [`Any`]: Self::Any
102	pub const fn first_address(&self) -> Option<IpAddr> {
103		match self {
104			Self::Any => None,
105			Self::V4(c) => Some(IpAddr::V4(c.first_address())),
106			Self::V6(c) => Some(IpAddr::V6(c.first_address())),
107		}
108	}
109
110	/// first address in the network
111	///
112	/// returns [`None`] for [`Any`]
113	///
114	/// [`Any`]: Self::Any
115	pub const fn first(&self) -> Option<IpInet> {
116		match self {
117			Self::Any => None,
118			Self::V4(c) => Some(IpInet::V4(c.first())),
119			Self::V6(c) => Some(IpInet::V6(c.first())),
120		}
121	}
122
123	/// last address in the network as plain address
124	///
125	/// returns [`None`] for [`Any`]
126	///
127	/// [`Any`]: Self::Any
128	pub const fn last_address(&self) -> Option<IpAddr> {
129		match self {
130			Self::Any => None,
131			Self::V4(c) => Some(IpAddr::V4(c.last_address())),
132			Self::V6(c) => Some(IpAddr::V6(c.last_address())),
133		}
134	}
135
136	/// last address in the network
137	///
138	/// returns [`None`] for [`Any`]
139	///
140	/// [`Any`]: Self::Any
141	pub const fn last(&self) -> Option<IpInet> {
142		match self {
143			Self::Any => None,
144			Self::V4(c) => Some(IpInet::V4(c.last())),
145			Self::V6(c) => Some(IpInet::V6(c.last())),
146		}
147	}
148
149	/// length in bits of the shared prefix of the contained addresses
150	///
151	/// returns [`None`] for [`Any`]
152	///
153	/// [`Any`]: Self::Any
154	pub const fn network_length(&self) -> Option<u8> {
155		match self {
156			Self::Any => None,
157			Self::V4(c) => Some(c.network_length()),
158			Self::V6(c) => Some(c.network_length()),
159		}
160	}
161
162	/// IP family of the contained address ([`Ipv4`] or [`Ipv6`]).
163	///
164	/// returns [`None`] for [`Any`]
165	///
166	/// [`Any`]: Self::Any
167	/// [`Ipv4`]: Family::Ipv4
168	/// [`Ipv6`]: Family::Ipv6
169	pub const fn family(&self) -> Option<Family> {
170		match self {
171			Self::Any => None,
172			Self::V4(_) => Some(Family::Ipv4),
173			Self::V6(_) => Some(Family::Ipv6),
174		}
175	}
176
177	/// whether network represents a single host address
178	pub const fn is_host_address(&self) -> bool {
179		match self {
180			Self::Any => false,
181			Self::V4(c) => c.is_host_address(),
182			Self::V6(c) => c.is_host_address(),
183		}
184	}
185
186	/// network mask: an pseudo address which has the first `network
187	/// length` bits set to 1 and the remaining to 0.
188	///
189	/// returns [`None`] for [`Any`]
190	///
191	/// [`Any`]: Self::Any
192	pub const fn mask(&self) -> Option<IpAddr> {
193		match self {
194			Self::Any => None,
195			Self::V4(c) => Some(IpAddr::V4(c.mask())),
196			Self::V6(c) => Some(IpAddr::V6(c.mask())),
197		}
198	}
199
200	/// check whether an address is contained in the network
201	pub const fn contains(&self, addr: &IpAddr) -> bool {
202		match self {
203			Self::Any => true,
204			Self::V4(c) => match addr {
205				IpAddr::V4(a) => c.contains(a),
206				IpAddr::V6(_) => false,
207			},
208			Self::V6(c) => match addr {
209				IpAddr::V4(_) => false,
210				IpAddr::V6(a) => c.contains(a),
211			},
212		}
213	}
214}
215
216impl fmt::Display for AnyIpCidr {
217	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218		match self {
219			Self::Any => write!(f, "any"),
220			Self::V4(c) => fmt::Display::fmt(c, f),
221			Self::V6(c) => fmt::Display::fmt(c, f),
222		}
223	}
224}
225
226impl From<AnyIpCidr> for Option<IpCidr> {
227	fn from(value: AnyIpCidr) -> Option<IpCidr> {
228		match value {
229			AnyIpCidr::Any => None,
230			AnyIpCidr::V4(c) => Some(IpCidr::V4(c)),
231			AnyIpCidr::V6(c) => Some(IpCidr::V6(c)),
232		}
233	}
234}
235
236impl From<Option<IpCidr>> for AnyIpCidr {
237	fn from(a: Option<IpCidr>) -> Self {
238		match a {
239			None => Self::Any,
240			Some(IpCidr::V4(c)) => Self::V4(c),
241			Some(IpCidr::V6(c)) => Self::V6(c),
242		}
243	}
244}
245
246impl FromStr for AnyIpCidr {
247	type Err = NetworkParseError;
248
249	fn from_str(s: &str) -> Result<Self, NetworkParseError> {
250		crate::parsers::parse_any_cidr(s, str::parse)
251	}
252}
253
254impl From<IpCidr> for AnyIpCidr {
255	fn from(c: IpCidr) -> Self {
256		match c {
257			IpCidr::V4(c) => Self::V4(c),
258			IpCidr::V6(c) => Self::V6(c),
259		}
260	}
261}
262
263impl From<Ipv4Cidr> for AnyIpCidr {
264	fn from(c: Ipv4Cidr) -> Self {
265		Self::V4(c)
266	}
267}
268
269impl From<Ipv4Addr> for AnyIpCidr {
270	fn from(address: Ipv4Addr) -> Self {
271		Self::V4(address.into())
272	}
273}
274
275impl From<Ipv6Cidr> for AnyIpCidr {
276	fn from(c: Ipv6Cidr) -> Self {
277		Self::V6(c)
278	}
279}
280
281impl From<Ipv6Addr> for AnyIpCidr {
282	fn from(address: Ipv6Addr) -> Self {
283		Self::V6(address.into())
284	}
285}
286
287impl From<IpAddr> for AnyIpCidr {
288	fn from(address: IpAddr) -> Self {
289		Self::new_host(address)
290	}
291}
292
293#[cfg(feature = "bitstring")]
294impl bitstring::BitString for AnyIpCidr {
295	fn get(&self, ndx: usize) -> bool {
296		assert!(!self.is_any());
297		if 0 == ndx {
298			self.is_ipv6()
299		} else {
300			match self {
301				Self::Any => unreachable!(),
302				Self::V4(c) => c.get(ndx - 1),
303				Self::V6(c) => c.get(ndx - 1),
304			}
305		}
306	}
307
308	fn set(&mut self, ndx: usize, bit: bool) {
309		assert!(!self.is_any());
310		if 0 == ndx {
311			if bit {
312				*self = Self::V6(Ipv6Cidr::null());
313			} else {
314				*self = Self::V4(Ipv4Cidr::null());
315			}
316		} else {
317			match self {
318				Self::Any => unreachable!(),
319				Self::V4(ref mut c) => c.set(ndx - 1, bit),
320				Self::V6(ref mut c) => c.set(ndx - 1, bit),
321			}
322		}
323	}
324
325	fn flip(&mut self, ndx: usize) {
326		assert!(!self.is_any());
327		if 0 == ndx {
328			if self.is_ipv6() {
329				*self = Self::V4(Ipv4Cidr::null())
330			} else {
331				*self = Self::V6(Ipv6Cidr::null())
332			}
333		} else {
334			match self {
335				Self::Any => unreachable!(),
336				Self::V4(ref mut c) => c.flip(ndx - 1),
337				Self::V6(ref mut c) => c.flip(ndx - 1),
338			}
339		}
340	}
341
342	fn len(&self) -> usize {
343		match self {
344			Self::Any => 0,
345			Self::V4(c) => c.len() + 1,
346			Self::V6(c) => c.len() + 1,
347		}
348	}
349
350	fn clip(&mut self, len: usize) {
351		// max length is 129 (len(IPv6) + 1)
352		if len > 128 {
353			return;
354		}
355		if 0 == len {
356			*self = Self::Any;
357		} else {
358			match self {
359				Self::Any => (),
360				Self::V4(ref mut c) => c.clip(len - 1),
361				Self::V6(ref mut c) => c.clip(len - 1),
362			}
363		}
364	}
365
366	fn append(&mut self, bit: bool) {
367		match self {
368			Self::Any => {
369				if bit {
370					*self = Self::V6(Ipv6Cidr::null());
371				} else {
372					*self = Self::V4(Ipv4Cidr::null());
373				}
374			},
375			Self::V4(ref mut c) => c.append(bit),
376			Self::V6(ref mut c) => c.append(bit),
377		}
378	}
379
380	fn null() -> Self {
381		Self::Any
382	}
383
384	fn shared_prefix_len(&self, other: &Self) -> usize {
385		match (self, other) {
386			(Self::V4(a), Self::V4(b)) => 1 + a.shared_prefix_len(b),
387			(Self::V6(a), Self::V6(b)) => 1 + a.shared_prefix_len(b),
388			_ => 0,
389		}
390	}
391}