1use crate::inet::{
5 ipv4::{IpV4Address, SocketAddressV4},
6 ipv6::{IpV6Address, SocketAddressV6},
7 unspecified::Unspecified,
8};
9use core::fmt;
10
11#[cfg(any(test, feature = "generator"))]
12use bolero_generator::prelude::*;
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
21#[cfg_attr(any(test, feature = "generator"), derive(TypeGenerator))]
22pub enum IpAddress {
23 Ipv4(IpV4Address),
24 Ipv6(IpV6Address),
25}
26
27impl IpAddress {
28 #[inline]
30 #[must_use]
31 pub fn unmap(self) -> Self {
32 match self {
33 Self::Ipv4(_) => self,
34 Self::Ipv6(addr) => addr.unmap(),
35 }
36 }
37
38 #[inline]
42 pub fn unmapped_eq(&self, other: &Self) -> bool {
43 self.unmap() == other.unmap()
44 }
45
46 #[inline]
48 #[must_use]
49 pub fn to_ipv6_mapped(self) -> IpV6Address {
50 match self {
51 Self::Ipv4(addr) => addr.to_ipv6_mapped(),
52 Self::Ipv6(addr) => addr,
53 }
54 }
55
56 #[inline]
57 #[must_use]
58 pub fn with_port(self, port: u16) -> SocketAddress {
59 match self {
60 Self::Ipv4(addr) => addr.with_port(port).into(),
61 Self::Ipv6(addr) => addr.with_port(port).into(),
62 }
63 }
64}
65
66impl From<IpV4Address> for IpAddress {
67 fn from(ip: IpV4Address) -> Self {
68 Self::Ipv4(ip)
69 }
70}
71
72impl From<IpV6Address> for IpAddress {
73 fn from(ip: IpV6Address) -> Self {
74 Self::Ipv6(ip)
75 }
76}
77
78impl Unspecified for IpAddress {
79 fn is_unspecified(&self) -> bool {
80 match self {
81 Self::Ipv4(addr) => addr.is_unspecified(),
82 Self::Ipv6(addr) => addr.is_unspecified(),
83 }
84 }
85}
86
87#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
88pub enum IpAddressRef<'a> {
89 IPv4(&'a IpV4Address),
90 IPv6(&'a IpV6Address),
91}
92
93impl IpAddressRef<'_> {
94 pub fn to_owned(self) -> IpAddress {
95 match self {
96 Self::IPv4(addr) => IpAddress::Ipv4(*addr),
97 Self::IPv6(addr) => IpAddress::Ipv6(*addr),
98 }
99 }
100}
101
102impl<'a> From<&'a IpV4Address> for IpAddressRef<'a> {
103 fn from(ip: &'a IpV4Address) -> Self {
104 Self::IPv4(ip)
105 }
106}
107
108impl<'a> From<&'a IpV6Address> for IpAddressRef<'a> {
109 fn from(ip: &'a IpV6Address) -> Self {
110 Self::IPv6(ip)
111 }
112}
113
114#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
121#[cfg_attr(any(test, feature = "generator"), derive(TypeGenerator))]
122#[cfg_attr(kani, derive(kani::Arbitrary))]
123pub enum SocketAddress {
124 IpV4(SocketAddressV4),
125 IpV6(SocketAddressV6),
126}
127
128impl SocketAddress {
129 #[inline]
130 pub fn ip(&self) -> IpAddress {
131 match self {
132 SocketAddress::IpV4(addr) => IpAddress::Ipv4(*addr.ip()),
133 SocketAddress::IpV6(addr) => IpAddress::Ipv6(*addr.ip()),
134 }
135 }
136
137 #[inline]
138 pub fn port(&self) -> u16 {
139 match self {
140 SocketAddress::IpV4(addr) => addr.port(),
141 SocketAddress::IpV6(addr) => addr.port(),
142 }
143 }
144
145 #[inline]
146 pub fn set_port(&mut self, port: u16) {
147 match self {
148 SocketAddress::IpV4(addr) => addr.set_port(port),
149 SocketAddress::IpV6(addr) => addr.set_port(port),
150 }
151 }
152
153 #[inline]
154 pub const fn unicast_scope(&self) -> Option<UnicastScope> {
155 match self {
156 Self::IpV4(addr) => addr.unicast_scope(),
157 Self::IpV6(addr) => addr.unicast_scope(),
158 }
159 }
160
161 pub fn to_ipv6_mapped(self) -> SocketAddressV6 {
163 match self {
164 Self::IpV4(addr) => addr.to_ipv6_mapped(),
165 Self::IpV6(addr) => addr,
166 }
167 }
168
169 #[inline]
171 #[must_use]
172 pub fn unmap(self) -> Self {
173 match self {
174 Self::IpV4(_) => self,
175 Self::IpV6(addr) => addr.unmap(),
176 }
177 }
178
179 #[inline]
183 pub fn unmapped_eq(&self, other: &Self) -> bool {
184 self.unmap() == other.unmap()
185 }
186}
187
188impl Default for SocketAddress {
189 fn default() -> Self {
190 SocketAddress::IpV4(Default::default())
191 }
192}
193
194impl fmt::Display for SocketAddress {
195 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
196 match self {
197 SocketAddress::IpV4(addr) => write!(fmt, "{addr}"),
198 SocketAddress::IpV6(addr) => write!(fmt, "{addr}"),
199 }
200 }
201}
202
203impl Unspecified for SocketAddress {
204 fn is_unspecified(&self) -> bool {
205 match self {
206 SocketAddress::IpV4(addr) => addr.is_unspecified(),
207 SocketAddress::IpV6(addr) => addr.is_unspecified(),
208 }
209 }
210}
211
212impl From<SocketAddressV4> for SocketAddress {
213 fn from(addr: SocketAddressV4) -> Self {
214 SocketAddress::IpV4(addr)
215 }
216}
217
218impl From<SocketAddressV6> for SocketAddress {
219 fn from(addr: SocketAddressV6) -> Self {
220 SocketAddress::IpV6(addr)
221 }
222}
223
224#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
229pub enum SocketAddressRef<'a> {
230 IpV4(&'a SocketAddressV4),
231 IpV6(&'a SocketAddressV6),
232}
233
234impl SocketAddressRef<'_> {
235 pub fn to_owned(self) -> SocketAddress {
236 match self {
237 Self::IpV4(addr) => SocketAddress::IpV4(*addr),
238 Self::IpV6(addr) => SocketAddress::IpV6(*addr),
239 }
240 }
241}
242
243#[derive(Clone, Copy, Debug, PartialEq, Eq)]
249pub enum UnicastScope {
250 Loopback,
251 LinkLocal,
252 Private,
253 Global,
254}
255
256#[cfg(any(test, feature = "std"))]
257mod std_conversion {
258 use super::*;
259 use std::net;
260
261 impl net::ToSocketAddrs for SocketAddress {
262 type Iter = std::iter::Once<net::SocketAddr>;
263
264 fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
265 match self {
266 Self::IpV4(addr) => addr.to_socket_addrs(),
267 Self::IpV6(addr) => addr.to_socket_addrs(),
268 }
269 }
270 }
271
272 impl net::ToSocketAddrs for SocketAddressRef<'_> {
273 type Iter = std::iter::Once<net::SocketAddr>;
274
275 fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
276 match self {
277 Self::IpV4(addr) => addr.to_socket_addrs(),
278 Self::IpV6(addr) => addr.to_socket_addrs(),
279 }
280 }
281 }
282
283 impl From<SocketAddress> for net::SocketAddr {
284 fn from(address: SocketAddress) -> Self {
285 match address {
286 SocketAddress::IpV4(addr) => addr.into(),
287 SocketAddress::IpV6(addr) => addr.into(),
288 }
289 }
290 }
291
292 impl From<(net::IpAddr, u16)> for SocketAddress {
293 fn from((ip, port): (net::IpAddr, u16)) -> Self {
294 match ip {
295 net::IpAddr::V4(ip) => Self::IpV4((ip, port).into()),
296 net::IpAddr::V6(ip) => Self::IpV6((ip, port).into()),
297 }
298 }
299 }
300
301 impl<'a> From<SocketAddressRef<'a>> for net::SocketAddr {
302 fn from(address: SocketAddressRef<'a>) -> Self {
303 match address {
304 SocketAddressRef::IpV4(addr) => addr.into(),
305 SocketAddressRef::IpV6(addr) => addr.into(),
306 }
307 }
308 }
309
310 impl From<net::SocketAddr> for SocketAddress {
311 fn from(addr: net::SocketAddr) -> Self {
312 match addr {
313 net::SocketAddr::V4(addr) => Self::IpV4(addr.into()),
314 net::SocketAddr::V6(addr) => Self::IpV6(addr.into()),
315 }
316 }
317 }
318}
319
320define_inet_type!(
321 pub struct Protocol {
322 id: u8,
323 }
324);
325
326impl fmt::Debug for Protocol {
327 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
328 f.debug_tuple("ip::Protocol")
329 .field(&format_args!("{self}"))
330 .finish()
331 }
332}
333
334impl fmt::Display for Protocol {
335 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
336 match *self {
337 Self::HOPOPT => "IPv6 Hop-by-Hop Option",
338 Self::ICMP => "Internet Control Message",
339 Self::IPV4 => "IPv4 Encapsulation",
340 Self::TCP => "Transmission Control",
341 Self::UDP => "User Datagram",
342 Self::IPV6 => "IPv6 Encapsulation",
343 Self::IPV6_ROUTE => "Routing Header for IPv6",
344 Self::IPV6_FRAG => "Fragment Header for IPv6",
345 Self::IPV6_ICMP => "ICMP for IPv6",
346 Self::IPV6_NO_NXT => "No Next Header for IPv6",
347 Self::IPV6_OPTS => "Destination Options for IPv6",
348 Self::UDPLITE => "Lightweight User Datagram",
349 Self { id } => return write!(f, "[unknown 0x{id:02x}]"),
350 }
351 .fmt(f)
352 }
353}
354
355macro_rules! impl_p {
356 ($fun:ident, $cap:ident, $val:literal) => {
357 pub const $cap: Self = Self { id: $val };
358
359 #[inline]
360 pub const fn $fun(self) -> bool {
361 self.id == $val
362 }
363 };
364}
365
366impl Protocol {
367 impl_p!(is_hop_by_hop, HOPOPT, 0);
371 impl_p!(is_icmp, ICMP, 1);
372 impl_p!(is_ipv4, IPV4, 4);
373 impl_p!(is_tcp, TCP, 6);
374 impl_p!(is_udp, UDP, 17);
375 impl_p!(is_ipv6, IPV6, 41);
376 impl_p!(is_ipv6_route, IPV6_ROUTE, 43);
377 impl_p!(is_ipv6_fragment, IPV6_FRAG, 44);
378 impl_p!(is_ipv6_icmp, IPV6_ICMP, 58);
379 impl_p!(is_ipv6_no_next, IPV6_NO_NXT, 59);
380 impl_p!(is_ipv6_options, IPV6_OPTS, 60);
381 impl_p!(is_udplite, UDPLITE, 136);
382}
383
384#[cfg(test)]
385mod tests {
386 use super::*;
387 use std::net::{SocketAddr, ToSocketAddrs};
388
389 const TESTS: &[&str] = &[
390 "127.0.0.1:80",
391 "192.168.1.1:40",
392 "255.255.255.255:12345",
393 "[::]:443",
394 "[::1]:123",
395 "[2001:0db8:85a3:0001:0002:8a2e:0370:7334]:9000",
396 ];
397
398 #[test]
399 fn to_ipv6_mapped_test() {
403 for test in TESTS.iter() {
404 let addr: SocketAddr = test.parse().unwrap();
406 let address: SocketAddress = addr.into();
407 let addr = match addr {
408 SocketAddr::V4(addr) => {
409 let ip = addr.ip().to_ipv6_mapped();
410 (ip, addr.port()).into()
411 }
412 _ => addr,
413 };
414 let address = address.to_ipv6_mapped().into();
415 assert_eq!(addr, address);
416 }
417 }
418
419 #[test]
420 fn unmap_test() {
421 for test in TESTS.iter() {
422 let addr: SocketAddr = test.parse().unwrap();
424 let address: SocketAddress = addr.into();
425 let actual: SocketAddress = address.to_ipv6_mapped().into();
426 let actual = actual.unmap();
427 assert_eq!(address, actual);
428 }
429 }
430
431 #[test]
432 fn display_test() {
433 for test in TESTS.iter() {
434 let addr: SocketAddr = test.parse().unwrap();
436 let address: SocketAddress = addr.into();
437 assert_eq!(addr.to_string(), address.to_string());
438 }
439 }
440
441 #[test]
442 fn to_socket_addrs_test() {
443 for test in TESTS.iter() {
444 let addr: SocketAddr = test.parse().unwrap();
445 let address: SocketAddress = addr.into();
446 for address in address.to_socket_addrs().unwrap() {
447 assert_eq!(addr, address);
448 }
449 }
450 }
451}