1use core::fmt::{self, Debug, Display, Formatter};
8use core::marker::PhantomData;
9use core::num::NonZeroU16;
10use core::ops::Deref;
11
12use derivative::Derivative;
13use net_types::ip::{GenericOverIp, Ip, IpAddress, Ipv4, Ipv4Addr, Ipv6Addr, Ipv6SourceAddr};
14use net_types::{
15 MulticastAddr, NonMappedAddr, ScopeableAddress, SpecifiedAddr, UnicastAddr, Witness, ZonedAddr,
16};
17
18use crate::socket::base::{
19 AddrVec, DualStackIpExt, EitherStack, SocketIpAddrExt as _, SocketIpExt, SocketMapAddrSpec,
20};
21
22#[derive(Copy, Clone, Eq, Hash, PartialEq)]
35pub struct StrictlyZonedAddr<A, W, Z> {
36 addr: ZonedAddr<W, Z>,
37 marker: PhantomData<A>,
38}
39
40impl<A: Debug, W: Debug, Z: Debug> Debug for StrictlyZonedAddr<A, W, Z> {
41 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
42 let StrictlyZonedAddr { addr, marker: PhantomData } = self;
43 write!(f, "{:?}", addr)
44 }
45}
46
47impl<A: IpAddress, W: Witness<A> + ScopeableAddress + Copy, Z> StrictlyZonedAddr<A, W, Z> {
48 pub fn into_inner(self) -> ZonedAddr<W, Z> {
50 let StrictlyZonedAddr { addr, marker: PhantomData } = self;
51 addr
52 }
53
54 pub fn into_inner_without_witness(self) -> ZonedAddr<A, Z> {
56 self.into_inner().map_addr(|addr| addr.into_addr())
57 }
58
59 pub fn new_with_zone(addr: W, get_zone: impl FnOnce() -> Z) -> Self {
68 if let Some(addr_and_zone) = addr.try_into_null_zoned() {
69 StrictlyZonedAddr {
70 addr: ZonedAddr::Zoned(addr_and_zone.map_zone(move |()| get_zone())),
71 marker: PhantomData,
72 }
73 } else {
74 StrictlyZonedAddr { addr: ZonedAddr::Unzoned(addr), marker: PhantomData }
75 }
76 }
77
78 #[cfg(feature = "testutils")]
79 pub fn new_unzoned_or_panic(addr: W) -> Self {
81 Self::new_with_zone(addr, || panic!("addr unexpectedly required a zone."))
82 }
83}
84
85impl<A: IpAddress, W: Witness<A>, Z> Deref for StrictlyZonedAddr<A, W, Z> {
86 type Target = ZonedAddr<W, Z>;
87 fn deref(&self) -> &Self::Target {
88 let StrictlyZonedAddr { addr, marker: PhantomData } = self;
89 addr
90 }
91}
92
93#[derive(Copy, Clone, Eq, GenericOverIp, Hash, PartialEq)]
102#[generic_over_ip(A, IpAddress)]
103pub struct SocketIpAddr<A: IpAddress>(NonMappedAddr<SpecifiedAddr<A>>);
104
105impl<A: IpAddress> Display for SocketIpAddr<A> {
106 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
107 let Self(addr) = self;
108 write!(f, "{}", addr)
109 }
110}
111
112impl<A: IpAddress> Debug for SocketIpAddr<A> {
113 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
114 let Self(addr) = self;
115 write!(f, "{:?}", addr)
116 }
117}
118
119impl<A: IpAddress> SocketIpAddr<A> {
120 pub fn new(addr: A) -> Option<SocketIpAddr<A>> {
122 Some(SocketIpAddr(NonMappedAddr::new(SpecifiedAddr::new(addr)?)?))
123 }
124
125 pub fn new_from_witness(addr: NonMappedAddr<SpecifiedAddr<A>>) -> Self {
127 Self(addr)
128 }
129
130 pub const unsafe fn new_unchecked(addr: A) -> SocketIpAddr<A> {
138 let non_mapped =
140 unsafe { NonMappedAddr::new_unchecked(SpecifiedAddr::new_unchecked(addr)) };
141 SocketIpAddr(non_mapped)
142 }
143
144 pub const unsafe fn new_from_specified_unchecked(addr: SpecifiedAddr<A>) -> SocketIpAddr<A> {
150 let non_mapped = unsafe { NonMappedAddr::new_unchecked(addr) };
152 SocketIpAddr(non_mapped)
153 }
154
155 pub fn addr(self) -> A {
157 let SocketIpAddr(addr) = self;
158 **addr
159 }
160
161 pub fn into_inner(self) -> NonMappedAddr<SpecifiedAddr<A>> {
163 let SocketIpAddr(addr) = self;
164 addr
165 }
166
167 pub fn new_from_multicast(addr: MulticastAddr<A>) -> SocketIpAddr<A> {
169 let addr: MulticastAddr<NonMappedAddr<_>> = addr.non_mapped().transpose();
170 let addr: NonMappedAddr<SpecifiedAddr<_>> = addr.into_specified().transpose();
171 SocketIpAddr(addr)
172 }
173}
174
175impl SocketIpAddr<Ipv4Addr> {
176 pub fn new_ipv4_specified(addr: SpecifiedAddr<Ipv4Addr>) -> Self {
178 addr.try_into().unwrap_or_else(|AddrIsMappedError {}| {
179 unreachable!("IPv4 addresses must be non-mapped")
180 })
181 }
182}
183
184impl SocketIpAddr<Ipv6Addr> {
185 pub fn new_from_ipv6_non_mapped_unicast(addr: NonMappedAddr<UnicastAddr<Ipv6Addr>>) -> Self {
187 let addr: UnicastAddr<NonMappedAddr<_>> = addr.transpose();
188 let addr: NonMappedAddr<SpecifiedAddr<_>> = addr.into_specified().transpose();
189 SocketIpAddr(addr)
190 }
191
192 pub fn new_from_ipv6_source(addr: Ipv6SourceAddr) -> Option<Self> {
195 match addr {
196 Ipv6SourceAddr::Unspecified => None,
197 Ipv6SourceAddr::Unicast(addr) => {
198 Some(SocketIpAddr::new_from_ipv6_non_mapped_unicast(addr))
199 }
200 }
201 }
202}
203
204impl<A: IpAddress> From<SocketIpAddr<A>> for SpecifiedAddr<A> {
205 fn from(addr: SocketIpAddr<A>) -> Self {
206 let SocketIpAddr(addr) = addr;
207 *addr
208 }
209}
210
211impl<A: IpAddress> AsRef<SpecifiedAddr<A>> for SocketIpAddr<A> {
212 fn as_ref(&self) -> &SpecifiedAddr<A> {
213 let SocketIpAddr(addr) = self;
214 addr.as_ref()
215 }
216}
217
218#[derive(Debug)]
222pub struct AddrIsMappedError {}
223
224impl<A: IpAddress> TryFrom<SpecifiedAddr<A>> for SocketIpAddr<A> {
225 type Error = AddrIsMappedError;
226 fn try_from(addr: SpecifiedAddr<A>) -> Result<Self, Self::Error> {
227 NonMappedAddr::new(addr).map(SocketIpAddr).ok_or(AddrIsMappedError {})
228 }
229}
230
231impl<A: IpAddress> ScopeableAddress for SocketIpAddr<A> {
233 type Scope = A::Scope;
234 fn scope(&self) -> Self::Scope {
235 let SocketIpAddr(addr) = self;
236 addr.scope()
237 }
238}
239
240#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
242#[generic_over_ip(A, IpAddress)]
243pub struct ListenerIpAddr<A: IpAddress, LI> {
244 pub addr: Option<SocketIpAddr<A>>,
246 pub identifier: LI,
248}
249
250impl<A: IpAddress, LI: Into<NonZeroU16>> Into<(Option<SpecifiedAddr<A>>, NonZeroU16)>
251 for ListenerIpAddr<A, LI>
252{
253 fn into(self) -> (Option<SpecifiedAddr<A>>, NonZeroU16) {
254 let Self { addr, identifier } = self;
255 (addr.map(Into::into), identifier.into())
256 }
257}
258
259#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, GenericOverIp)]
261#[generic_over_ip(A, GenericOverIp)]
262pub struct ListenerAddr<A, D> {
263 pub ip: A,
265 pub device: Option<D>,
267}
268
269impl<A, D> AsRef<Option<D>> for ListenerAddr<A, D> {
270 fn as_ref(&self) -> &Option<D> {
271 &self.device
272 }
273}
274
275impl<TA, OA, D> AsRef<Option<D>> for EitherStack<ListenerAddr<TA, D>, ListenerAddr<OA, D>> {
276 fn as_ref(&self) -> &Option<D> {
277 match self {
278 EitherStack::ThisStack(l) => &l.device,
279 EitherStack::OtherStack(l) => &l.device,
280 }
281 }
282}
283
284#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
286#[generic_over_ip(A, IpAddress)]
287pub struct ConnIpAddrInner<A, LI, RI> {
288 pub local: (A, LI),
290 pub remote: (A, RI),
292}
293
294pub type ConnIpAddr<A, LI, RI> = ConnIpAddrInner<SocketIpAddr<A>, LI, RI>;
296pub type ConnInfoAddr<A, RI> = ConnIpAddrInner<SpecifiedAddr<A>, NonZeroU16, RI>;
298
299impl<A: IpAddress, LI: Into<NonZeroU16>, RI> From<ConnIpAddr<A, LI, RI>> for ConnInfoAddr<A, RI> {
300 fn from(
301 ConnIpAddr { local: (local_ip, local_identifier), remote: (remote_ip, remote_identifier) }: ConnIpAddr<A, LI, RI>,
302 ) -> Self {
303 Self {
304 local: (local_ip.into(), local_identifier.into()),
305 remote: (remote_ip.into(), remote_identifier),
306 }
307 }
308}
309
310#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
312#[generic_over_ip()]
313pub struct ConnAddr<A, D> {
314 pub ip: A,
316 pub device: Option<D>,
318}
319
320#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
322pub enum DualStackListenerIpAddr<A: IpAddress, LI: Into<NonZeroU16>>
323where
324 A::Version: DualStackIpExt,
325{
326 ThisStack(ListenerIpAddr<A, LI>),
328 OtherStack(ListenerIpAddr<<<A::Version as DualStackIpExt>::OtherVersion as Ip>::Addr, LI>),
330 BothStacks(LI),
332}
333
334impl<A: IpAddress, NewIp: DualStackIpExt, LI: Into<NonZeroU16>> GenericOverIp<NewIp>
335 for DualStackListenerIpAddr<A, LI>
336where
337 A::Version: DualStackIpExt,
338{
339 type Type = DualStackListenerIpAddr<NewIp::Addr, LI>;
340}
341
342impl<LI: Into<NonZeroU16>> Into<(Option<SpecifiedAddr<Ipv6Addr>>, NonZeroU16)>
343 for DualStackListenerIpAddr<Ipv6Addr, LI>
344{
345 fn into(self) -> (Option<SpecifiedAddr<Ipv6Addr>>, NonZeroU16) {
346 match self {
347 Self::ThisStack(listener_ip_addr) => listener_ip_addr.into(),
348 Self::OtherStack(ListenerIpAddr { addr, identifier }) => (
349 Some(addr.map_or(Ipv4::UNSPECIFIED_ADDRESS, SocketIpAddr::addr).to_ipv6_mapped()),
350 identifier.into(),
351 ),
352 Self::BothStacks(identifier) => (None, identifier.into()),
353 }
354 }
355}
356
357#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
359#[allow(missing_docs)]
360pub enum DualStackConnIpAddr<A: IpAddress, LI, RI>
361where
362 A::Version: DualStackIpExt,
363{
364 ThisStack(ConnIpAddr<A, LI, RI>),
365 OtherStack(ConnIpAddr<<<A::Version as DualStackIpExt>::OtherVersion as Ip>::Addr, LI, RI>),
366}
367
368impl<A: IpAddress, NewIp: DualStackIpExt, LI, RI> GenericOverIp<NewIp>
369 for DualStackConnIpAddr<A, LI, RI>
370where
371 A::Version: DualStackIpExt,
372{
373 type Type = DualStackConnIpAddr<NewIp::Addr, LI, RI>;
374}
375
376impl<LI: Into<NonZeroU16>, RI> From<DualStackConnIpAddr<Ipv6Addr, LI, RI>>
377 for ConnInfoAddr<Ipv6Addr, RI>
378{
379 fn from(addr: DualStackConnIpAddr<Ipv6Addr, LI, RI>) -> Self {
380 match addr {
381 DualStackConnIpAddr::ThisStack(conn_ip_addr) => conn_ip_addr.into(),
382 DualStackConnIpAddr::OtherStack(ConnIpAddr {
383 local: (local_ip, local_identifier),
384 remote: (remote_ip, remote_identifier),
385 }) => ConnInfoAddr {
386 local: (local_ip.addr().to_ipv6_mapped(), local_identifier.into()),
387 remote: (remote_ip.addr().to_ipv6_mapped(), remote_identifier),
388 },
389 }
390 }
391}
392
393impl<I: Ip, A: SocketMapAddrSpec> From<ListenerIpAddr<I::Addr, A::LocalIdentifier>>
394 for IpAddrVec<I, A>
395{
396 fn from(listener: ListenerIpAddr<I::Addr, A::LocalIdentifier>) -> Self {
397 IpAddrVec::Listener(listener)
398 }
399}
400
401impl<I: Ip, A: SocketMapAddrSpec> From<ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>>
402 for IpAddrVec<I, A>
403{
404 fn from(conn: ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>) -> Self {
405 IpAddrVec::Connected(conn)
406 }
407}
408
409impl<I: Ip, D, A: SocketMapAddrSpec>
410 From<ListenerAddr<ListenerIpAddr<I::Addr, A::LocalIdentifier>, D>> for AddrVec<I, D, A>
411{
412 fn from(listener: ListenerAddr<ListenerIpAddr<I::Addr, A::LocalIdentifier>, D>) -> Self {
413 AddrVec::Listen(listener)
414 }
415}
416
417impl<I: Ip, D, A: SocketMapAddrSpec>
418 From<ConnAddr<ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>, D>>
419 for AddrVec<I, D, A>
420{
421 fn from(
422 conn: ConnAddr<ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>, D>,
423 ) -> Self {
424 AddrVec::Conn(conn)
425 }
426}
427
428#[derive(Derivative)]
431#[derivative(
432 Debug(bound = ""),
433 Clone(bound = ""),
434 Eq(bound = ""),
435 PartialEq(bound = ""),
436 Hash(bound = "")
437)]
438#[allow(missing_docs)]
439pub enum IpAddrVec<I: Ip, A: SocketMapAddrSpec> {
440 Listener(ListenerIpAddr<I::Addr, A::LocalIdentifier>),
441 Connected(ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>),
442}
443
444impl<I: Ip, A: SocketMapAddrSpec> IpAddrVec<I, A> {
445 fn with_device<D>(self, device: Option<D>) -> AddrVec<I, D, A> {
446 match self {
447 IpAddrVec::Listener(ip) => AddrVec::Listen(ListenerAddr { ip, device }),
448 IpAddrVec::Connected(ip) => AddrVec::Conn(ConnAddr { ip, device }),
449 }
450 }
451}
452
453impl<I: Ip, A: SocketMapAddrSpec> IpAddrVec<I, A> {
454 fn widen(self) -> Option<Self> {
461 match self {
462 IpAddrVec::Listener(ListenerIpAddr { addr: None, identifier }) => {
463 let _: A::LocalIdentifier = identifier;
464 None
465 }
466 IpAddrVec::Connected(ConnIpAddr { local: (local_ip, local_identifier), remote }) => {
467 let _: (SocketIpAddr<I::Addr>, A::RemoteIdentifier) = remote;
468 Some(ListenerIpAddr { addr: Some(local_ip), identifier: local_identifier })
469 }
470 IpAddrVec::Listener(ListenerIpAddr { addr: Some(addr), identifier }) => {
471 let _: SocketIpAddr<I::Addr> = addr;
472 Some(ListenerIpAddr { addr: None, identifier })
473 }
474 }
475 .map(IpAddrVec::Listener)
476 }
477}
478
479pub(crate) enum AddrVecIterInner<I: Ip, D, A: SocketMapAddrSpec> {
480 WithDevice { device: D, emitted_device: bool, addr: IpAddrVec<I, A> },
481 NoDevice { addr: IpAddrVec<I, A> },
482 Done,
483}
484
485impl<I: Ip, D: Clone, A: SocketMapAddrSpec> Iterator for AddrVecIterInner<I, D, A> {
486 type Item = AddrVec<I, D, A>;
487
488 fn next(&mut self) -> Option<Self::Item> {
489 match self {
490 Self::Done => None,
491 Self::WithDevice { device, emitted_device, addr } => {
492 if !*emitted_device {
493 *emitted_device = true;
494 Some(addr.clone().with_device(Some(device.clone())))
495 } else {
496 let r = addr.clone().with_device(None);
497 if let Some(next) = addr.clone().widen() {
498 *addr = next;
499 *emitted_device = false;
500 } else {
501 *self = Self::Done;
502 }
503 Some(r)
504 }
505 }
506 Self::NoDevice { addr } => {
507 let r = addr.clone().with_device(None);
508 if let Some(next) = addr.clone().widen() {
509 *addr = next;
510 } else {
511 *self = Self::Done
512 }
513 Some(r)
514 }
515 }
516 }
517}
518
519pub struct AddrVecIter<I: Ip, D, A: SocketMapAddrSpec>(AddrVecIterInner<I, D, A>);
532
533impl<I: Ip, D, A: SocketMapAddrSpec> AddrVecIter<I, D, A> {
534 pub fn with_device(addr: IpAddrVec<I, A>, device: D) -> Self {
536 Self(AddrVecIterInner::WithDevice { device, emitted_device: false, addr })
537 }
538
539 pub fn without_device(addr: IpAddrVec<I, A>) -> Self {
541 Self(AddrVecIterInner::NoDevice { addr })
542 }
543}
544
545impl<I: Ip, D: Clone, A: SocketMapAddrSpec> Iterator for AddrVecIter<I, D, A> {
546 type Item = AddrVec<I, D, A>;
547
548 fn next(&mut self) -> Option<Self::Item> {
549 let Self(it) = self;
550 it.next()
551 }
552}
553
554#[derive(GenericOverIp)]
555#[generic_over_ip(I, Ip)]
556enum TryUnmapResult<I: DualStackIpExt, D> {
557 CannotBeUnmapped(ZonedAddr<SocketIpAddr<I::Addr>, D>),
561 Mapped(Option<ZonedAddr<SocketIpAddr<<I::OtherVersion as Ip>::Addr>, D>>),
568}
569
570fn try_unmap<A: IpAddress, D>(addr: ZonedAddr<SpecifiedAddr<A>, D>) -> TryUnmapResult<A::Version, D>
581where
582 A::Version: DualStackIpExt,
583{
584 <A::Version as Ip>::map_ip(
585 addr,
586 |v4| {
587 let addr = SocketIpAddr::new_ipv4_specified(v4.addr());
588 TryUnmapResult::CannotBeUnmapped(ZonedAddr::Unzoned(addr))
589 },
590 |v6| match v6.addr().to_ipv4_mapped() {
591 Some(v4) => {
592 let addr = SpecifiedAddr::new(v4).map(SocketIpAddr::new_ipv4_specified);
593 TryUnmapResult::Mapped(addr.map(ZonedAddr::Unzoned))
594 }
595 None => {
596 let (addr, zone) = v6.into_addr_zone();
597 let addr: SocketIpAddr<_> =
598 addr.try_into().unwrap_or_else(|AddrIsMappedError {}| {
599 unreachable!(
600 "addr cannot be mapped because `to_ipv4_mapped` returned `None`"
601 )
602 });
603 TryUnmapResult::CannotBeUnmapped(ZonedAddr::new(addr, zone).unwrap_or_else(|| {
604 unreachable!("addr should still be scopeable after wrapping in `SocketIpAddr`")
605 }))
606 }
607 },
608 )
609}
610
611fn specify_unspecified_remote<I: SocketIpExt, A: From<SocketIpAddr<I::Addr>>, Z>(
618 addr: Option<ZonedAddr<A, Z>>,
619) -> ZonedAddr<A, Z> {
620 addr.unwrap_or_else(|| ZonedAddr::Unzoned(I::LOOPBACK_ADDRESS_AS_SOCKET_IP_ADDR.into()))
621}
622
623#[allow(missing_docs)]
625pub enum DualStackRemoteIp<I: DualStackIpExt, D> {
626 ThisStack(ZonedAddr<SocketIpAddr<I::Addr>, D>),
627 OtherStack(ZonedAddr<SocketIpAddr<<I::OtherVersion as Ip>::Addr>, D>),
628}
629
630impl<I: SocketIpExt + DualStackIpExt<OtherVersion: SocketIpExt>, D> DualStackRemoteIp<I, D> {
631 pub fn new(remote_ip: Option<ZonedAddr<SpecifiedAddr<I::Addr>, D>>) -> Self {
637 let remote_ip = specify_unspecified_remote::<I, _, _>(remote_ip);
638 match try_unmap(remote_ip) {
639 TryUnmapResult::CannotBeUnmapped(remote_ip) => Self::ThisStack(remote_ip),
640 TryUnmapResult::Mapped(remote_ip) => {
641 let remote_ip = specify_unspecified_remote::<I::OtherVersion, _, _>(remote_ip);
648 Self::OtherStack(remote_ip)
649 }
650 }
651 }
652}
653
654#[allow(missing_docs)]
656pub enum DualStackLocalIp<I: DualStackIpExt, D> {
657 ThisStack(ZonedAddr<SocketIpAddr<I::Addr>, D>),
658 OtherStack(Option<ZonedAddr<SocketIpAddr<<I::OtherVersion as Ip>::Addr>, D>>),
659}
660
661impl<I: SocketIpExt + DualStackIpExt<OtherVersion: SocketIpExt>, D> DualStackLocalIp<I, D> {
662 pub fn new(local_ip: ZonedAddr<SpecifiedAddr<I::Addr>, D>) -> Self {
667 match try_unmap(local_ip) {
668 TryUnmapResult::CannotBeUnmapped(local_ip) => Self::ThisStack(local_ip),
669 TryUnmapResult::Mapped(local_ip) => Self::OtherStack(local_ip),
670 }
671 }
672}