1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
2
3use ipnet::{IpNet, Ipv4Net, Ipv6Net, PrefixLenError};
4
5macro_rules! if_net {
6 ($kind:literal) => {
7 paste::paste! {
8 #[doc = "An interface IP" $kind " network."]
9 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
10 pub struct [<If $kind Net>] {
11 index: u32,
12 addr: [<Ip $kind Net>],
13 }
14
15 impl core::fmt::Display for [<If $kind Net>] {
16 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
17 write!(f, "{} ({})", self.addr, self.index)
18 }
19 }
20
21 impl core::ops::Deref for [<If $kind Net>] {
22 type Target = [<Ip $kind Net>];
23
24 #[inline]
25 fn deref(&self) -> &Self::Target {
26 &self.addr
27 }
28 }
29
30 impl [<If $kind Net>] {
31 #[doc = "Creates a new `If" $kind "Net` from an [`Ip" $kind "Net`]."]
32 #[inline]
33 pub const fn new(index: u32, addr: [<Ip $kind Net>]) -> Self {
34 Self {
35 index,
36 addr,
37 }
38 }
39
40 #[doc = "Creates a new IP" $kind "interface address from an index, [`Ip" $kind "Addr`] and prefix length."]
41 #[inline]
42 pub const fn with_prefix_len(index: u32, addr: [<Ip $kind Addr>], prefix_len: u8) -> Result<Self, PrefixLenError> {
43 match [<Ip $kind Net>]::new(addr, prefix_len) {
44 Ok(net) => Ok(Self::new(index, net)),
45 Err(err) => Err(err),
46 }
47 }
48
49 #[doc = "Creates a new IP" $kind " interface address from an index, [`Ip" $kind "Addr`] and prefix length."]
50 #[inline]
53 pub const fn with_prefix_len_assert(index: u32, addr: [<Ip $kind Addr>], prefix_len: u8) -> Self {
54 Self { index, addr: [<Ip $kind Net>]::new_assert(addr, prefix_len) }
55 }
56
57 #[inline]
59 pub const fn index(&self) -> u32 {
60 self.index
61 }
62
63 pub fn name(&self) -> std::io::Result<smol_str::SmolStr> {
67 crate::idx_to_name::ifindex_to_name(self.index)
68 }
69
70 #[inline]
72 pub const fn addr(&self) -> [<Ip $kind Addr>] {
73 self.addr.addr()
74 }
75
76 #[inline]
78 pub const fn net(&self) -> &[<Ip $kind Net>] {
79 &self.addr
80 }
81
82 #[inline]
84 pub const fn prefix_len(&self) -> u8 {
85 self.addr.prefix_len()
86 }
87
88 #[inline]
90 pub const fn max_prefix_len(&self) -> u8 {
91 self.addr.max_prefix_len()
92 }
93 }
94 }
95 };
96}
97
98if_net!("v4");
99if_net!("v6");
100
101#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
103pub enum IfNet {
104 V4(Ifv4Net),
106 V6(Ifv6Net),
108}
109
110impl core::fmt::Display for IfNet {
111 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
112 match self {
113 Self::V4(addr) => write!(f, "{addr}"),
114 Self::V6(addr) => write!(f, "{addr}"),
115 }
116 }
117}
118
119impl From<Ifv4Net> for IfNet {
120 fn from(value: Ifv4Net) -> Self {
121 Self::V4(value)
122 }
123}
124
125impl From<Ifv6Net> for IfNet {
126 fn from(value: Ifv6Net) -> Self {
127 Self::V6(value)
128 }
129}
130
131impl IfNet {
132 #[inline]
134 pub const fn from_net(index: u32, addr: IpNet) -> Self {
135 match addr {
136 IpNet::V4(addr) => Self::V4(Ifv4Net::new(index, addr)),
137 IpNet::V6(addr) => Self::V6(Ifv6Net::new(index, addr)),
138 }
139 }
140
141 #[inline]
143 pub const fn with_prefix_len(
144 index: u32,
145 addr: IpAddr,
146 prefix_len: u8,
147 ) -> Result<Self, PrefixLenError> {
148 match addr {
149 IpAddr::V4(addr) => match Ifv4Net::with_prefix_len(index, addr, prefix_len) {
150 Ok(addr) => Ok(Self::V4(addr)),
151 Err(err) => Err(err),
152 },
153 IpAddr::V6(addr) => match Ifv6Net::with_prefix_len(index, addr, prefix_len) {
154 Ok(addr) => Ok(Self::V6(addr)),
155 Err(err) => Err(err),
156 },
157 }
158 }
159
160 #[inline]
164 pub const fn with_prefix_len_assert(index: u32, addr: IpAddr, prefix_len: u8) -> Self {
165 match addr {
166 IpAddr::V4(addr) => Self::V4(Ifv4Net::with_prefix_len_assert(index, addr, prefix_len)),
167 IpAddr::V6(addr) => Self::V6(Ifv6Net::with_prefix_len_assert(index, addr, prefix_len)),
168 }
169 }
170
171 #[inline]
173 pub const fn index(&self) -> u32 {
174 match self {
175 Self::V4(addr) => addr.index(),
176 Self::V6(addr) => addr.index(),
177 }
178 }
179
180 pub fn name(&self) -> std::io::Result<smol_str::SmolStr> {
184 crate::idx_to_name::ifindex_to_name(self.index())
185 }
186
187 #[inline]
189 pub const fn addr(&self) -> IpAddr {
190 match self {
191 Self::V4(addr) => IpAddr::V4(addr.addr()),
192 Self::V6(addr) => IpAddr::V6(addr.addr()),
193 }
194 }
195
196 #[inline]
198 pub const fn net(&self) -> IpNet {
199 match self {
200 Self::V4(addr) => IpNet::V4(*addr.net()),
201 Self::V6(addr) => IpNet::V6(*addr.net()),
202 }
203 }
204
205 #[inline]
207 pub const fn prefix_len(&self) -> u8 {
208 match self {
209 Self::V4(addr) => addr.addr.prefix_len(),
210 Self::V6(addr) => addr.addr.prefix_len(),
211 }
212 }
213
214 #[inline]
216 pub const fn max_prefix_len(&self) -> u8 {
217 match self {
218 Self::V4(addr) => addr.addr.max_prefix_len(),
219 Self::V6(addr) => addr.addr.max_prefix_len(),
220 }
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 #[test]
229 fn test_ifv4_net() {
230 let addr = Ipv4Addr::new(192, 168, 1, 1);
231 let net = Ifv4Net::with_prefix_len_assert(1, addr, 24);
232 assert_eq!(net.index(), 1);
233 assert_eq!(net.addr(), addr);
234 assert_eq!(net.prefix_len(), 24);
235 assert_eq!(net.max_prefix_len(), 32);
236 assert!(net.name().is_ok());
237 net.hostmask();
238 }
239
240 #[test]
241 fn test_ifv6_net() {
242 let addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1);
243 let net = Ifv6Net::with_prefix_len_assert(1, addr, 64);
244 assert_eq!(net.index(), 1);
245 assert_eq!(net.addr(), addr);
246 assert_eq!(net.prefix_len(), 64);
247 assert_eq!(net.max_prefix_len(), 128);
248 assert!(net.name().is_ok());
249 net.hostmask();
250 }
251
252 #[test]
253 fn test_if_net() {
254 let ipnet = IpNet::V4(Ipv4Net::new_assert(Ipv4Addr::new(192, 168, 1, 1), 24));
255 let from_ipnet = IfNet::from_net(1, ipnet);
256
257 let addr = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1));
258 let net = IfNet::with_prefix_len(1, addr, 24).unwrap();
259 let net1 = IfNet::with_prefix_len_assert(1, addr, 24);
260 assert_eq!(net, net1);
261 assert_eq!(net, from_ipnet);
262 assert_eq!(net.index(), 1);
263 assert_eq!(net.addr(), addr);
264 assert_eq!(net.prefix_len(), 24);
265 assert_eq!(net.max_prefix_len(), 32);
266 assert!(net.name().is_ok());
267 assert_eq!(
268 net.net(),
269 IpNet::V4(Ipv4Net::new_assert(Ipv4Addr::new(192, 168, 1, 1), 24))
270 );
271
272 let ipnet = IpNet::V6(Ipv6Net::new_assert(
273 Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1),
274 64,
275 ));
276 let from_ipnet = IfNet::from_net(1, ipnet);
277
278 let addr = IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
279 let net = IfNet::with_prefix_len(1, addr, 64).unwrap();
280 let net1 = IfNet::with_prefix_len_assert(1, addr, 64);
281 assert_eq!(net, net1);
282 assert_eq!(net, from_ipnet);
283 assert_eq!(net.index(), 1);
284 assert_eq!(net.addr(), addr);
285 assert_eq!(net.prefix_len(), 64);
286 assert_eq!(net.max_prefix_len(), 128);
287 assert!(net.name().is_ok());
288 assert_eq!(
289 net.net(),
290 IpNet::V6(Ipv6Net::new_assert(
291 Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1),
292 64
293 ))
294 );
295 }
296}