netstack3_base/socket/
address.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! A collection of types that represent the various parts of socket addresses.
6
7use 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/// A [`ZonedAddr`] whose address is `Zoned` iff a zone is required.
23///
24/// Any address whose scope can have a zone, will be the `Zoned` variant. The
25/// one exception is the loopback address, which is represented as `Unzoned`.
26/// This is because the loopback address is allowed to have, but does not
27/// require having, a zone.
28///
29/// # Type Parameters
30///
31/// A: The base [`IpAddress`] type.
32/// W: The [`Witness`] types of the `A`.
33/// Z: The zone of `A`.
34#[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    /// Convert self into the inner [`ZonedAddr`]
49    pub fn into_inner(self) -> ZonedAddr<W, Z> {
50        let StrictlyZonedAddr { addr, marker: PhantomData } = self;
51        addr
52    }
53
54    /// Convert self into the inner [`ZonedAddr`] while discarding the witness.
55    pub fn into_inner_without_witness(self) -> ZonedAddr<A, Z> {
56        self.into_inner().map_addr(|addr| addr.into_addr())
57    }
58
59    /// Creates from a specified IP address and an optional zone.
60    ///
61    /// If `addr` requires a zone, then `get_zone` will be called to provide
62    /// the zone.
63    ///
64    /// # Panics
65    /// This method panics if the `addr` wants a zone and `get_zone` will panic
66    /// when called.
67    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    /// Creates the unzoned variant, or panics if the addr's scope needs a zone.
80    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/// An IP address that witnesses all required properties of a socket address.
94///
95/// Requires `SpecifiedAddr` because most contexts do not permit unspecified
96/// addresses; those that do can hold a `Option<SocketIpAddr>`.
97///
98/// Requires `NonMappedAddr` because mapped addresses (i.e. ipv4-mapped-ipv6
99/// addresses) are converted from their original IP version to their target IP
100/// version when entering the stack.
101#[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    /// Constructs a [`SocketIpAddr`] if the address is compliant, else `None`.
121    pub fn new(addr: A) -> Option<SocketIpAddr<A>> {
122        Some(SocketIpAddr(NonMappedAddr::new(SpecifiedAddr::new(addr)?)?))
123    }
124
125    /// Constructs a [`SocketIpAddr`] from the inner witness.
126    pub fn new_from_witness(addr: NonMappedAddr<SpecifiedAddr<A>>) -> Self {
127        Self(addr)
128    }
129
130    /// Constructs a [`SocketIpAddr`] without verify the address's properties.
131    ///
132    ///
133    /// # Safety
134    ///
135    /// Callers must ensure that the addr is both a [`SpecifiedAddr`] and
136    /// a [`NonMappedAddr`].
137    pub const unsafe fn new_unchecked(addr: A) -> SocketIpAddr<A> {
138        SocketIpAddr(NonMappedAddr::new_unchecked(SpecifiedAddr::new_unchecked(addr)))
139    }
140
141    /// Like [`SocketIpAddr::new_unchecked`], but the address is specified.
142    ///
143    /// # Safety
144    ///
145    /// Callers must ensure that the addr is a [`NonMappedAddr`].
146    pub const unsafe fn new_from_specified_unchecked(addr: SpecifiedAddr<A>) -> SocketIpAddr<A> {
147        SocketIpAddr(NonMappedAddr::new_unchecked(addr))
148    }
149
150    /// Returns the inner address, dropping all witnesses.
151    pub fn addr(self) -> A {
152        let SocketIpAddr(addr) = self;
153        **addr
154    }
155
156    /// Returns the inner address, including all witness types.
157    pub fn into_inner(self) -> NonMappedAddr<SpecifiedAddr<A>> {
158        let SocketIpAddr(addr) = self;
159        addr
160    }
161
162    /// Constructs a [`SocketIpAddr`] from the given multicast address.
163    pub fn new_from_multicast(addr: MulticastAddr<A>) -> SocketIpAddr<A> {
164        let addr: MulticastAddr<NonMappedAddr<_>> = addr.non_mapped().transpose();
165        let addr: NonMappedAddr<SpecifiedAddr<_>> = addr.into_specified().transpose();
166        SocketIpAddr(addr)
167    }
168}
169
170impl SocketIpAddr<Ipv4Addr> {
171    /// Constructs a [`SocketIpAddr`] from a given specified IPv4 address.
172    pub fn new_ipv4_specified(addr: SpecifiedAddr<Ipv4Addr>) -> Self {
173        addr.try_into().unwrap_or_else(|AddrIsMappedError {}| {
174            unreachable!("IPv4 addresses must be non-mapped")
175        })
176    }
177}
178
179impl SocketIpAddr<Ipv6Addr> {
180    /// Constructs a [`SocketIpAddr`] from the given [`Ipv6DeviceAddr`].
181    pub fn new_from_ipv6_non_mapped_unicast(addr: NonMappedAddr<UnicastAddr<Ipv6Addr>>) -> Self {
182        let addr: UnicastAddr<NonMappedAddr<_>> = addr.transpose();
183        let addr: NonMappedAddr<SpecifiedAddr<_>> = addr.into_specified().transpose();
184        SocketIpAddr(addr)
185    }
186
187    /// Optionally constructs a [`SocketIpAddr`] from the given
188    /// [`Ipv6SourceAddr`], returning `None` if the given addr is `Unspecified`.
189    pub fn new_from_ipv6_source(addr: Ipv6SourceAddr) -> Option<Self> {
190        match addr {
191            Ipv6SourceAddr::Unspecified => None,
192            Ipv6SourceAddr::Unicast(addr) => {
193                Some(SocketIpAddr::new_from_ipv6_non_mapped_unicast(addr))
194            }
195        }
196    }
197}
198
199impl<A: IpAddress> From<SocketIpAddr<A>> for SpecifiedAddr<A> {
200    fn from(addr: SocketIpAddr<A>) -> Self {
201        let SocketIpAddr(addr) = addr;
202        *addr
203    }
204}
205
206impl<A: IpAddress> AsRef<SpecifiedAddr<A>> for SocketIpAddr<A> {
207    fn as_ref(&self) -> &SpecifiedAddr<A> {
208        let SocketIpAddr(addr) = self;
209        addr.as_ref()
210    }
211}
212
213/// The addr could not be converted to a `NonMappedAddr`.
214///
215/// Perhaps the address was an ipv4-mapped-ipv6 addresses.
216#[derive(Debug)]
217pub struct AddrIsMappedError {}
218
219impl<A: IpAddress> TryFrom<SpecifiedAddr<A>> for SocketIpAddr<A> {
220    type Error = AddrIsMappedError;
221    fn try_from(addr: SpecifiedAddr<A>) -> Result<Self, Self::Error> {
222        NonMappedAddr::new(addr).map(SocketIpAddr).ok_or(AddrIsMappedError {})
223    }
224}
225
226/// Allows [`SocketIpAddr`] to be used inside of a [`ZonedAddr`].
227impl<A: IpAddress> ScopeableAddress for SocketIpAddr<A> {
228    type Scope = A::Scope;
229    fn scope(&self) -> Self::Scope {
230        let SocketIpAddr(addr) = self;
231        addr.scope()
232    }
233}
234
235/// The IP address and identifier (port) of a listening socket.
236#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
237#[generic_over_ip(A, IpAddress)]
238pub struct ListenerIpAddr<A: IpAddress, LI> {
239    /// The specific address being listened on, or `None` for all addresses.
240    pub addr: Option<SocketIpAddr<A>>,
241    /// The local identifier (i.e. port for TCP/UDP).
242    pub identifier: LI,
243}
244
245impl<A: IpAddress, LI: Into<NonZeroU16>> Into<(Option<SpecifiedAddr<A>>, NonZeroU16)>
246    for ListenerIpAddr<A, LI>
247{
248    fn into(self) -> (Option<SpecifiedAddr<A>>, NonZeroU16) {
249        let Self { addr, identifier } = self;
250        (addr.map(Into::into), identifier.into())
251    }
252}
253
254/// The address of a listening socket.
255#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, GenericOverIp)]
256#[generic_over_ip(A, GenericOverIp)]
257pub struct ListenerAddr<A, D> {
258    /// The IP address of the listening socket.
259    pub ip: A,
260    /// The bound device of the listening socket.
261    pub device: Option<D>,
262}
263
264impl<A, D> AsRef<Option<D>> for ListenerAddr<A, D> {
265    fn as_ref(&self) -> &Option<D> {
266        &self.device
267    }
268}
269
270impl<TA, OA, D> AsRef<Option<D>> for EitherStack<ListenerAddr<TA, D>, ListenerAddr<OA, D>> {
271    fn as_ref(&self) -> &Option<D> {
272        match self {
273            EitherStack::ThisStack(l) => &l.device,
274            EitherStack::OtherStack(l) => &l.device,
275        }
276    }
277}
278
279/// The IP addresses and identifiers (ports) of a connected socket.
280#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
281#[generic_over_ip(A, IpAddress)]
282pub struct ConnIpAddrInner<A, LI, RI> {
283    /// The local address, port tuple.
284    pub local: (A, LI),
285    /// The remote address, port tuple.
286    pub remote: (A, RI),
287}
288
289/// The IP addresses and identifiers (ports) of a connected socket.
290pub type ConnIpAddr<A, LI, RI> = ConnIpAddrInner<SocketIpAddr<A>, LI, RI>;
291/// The IP addresses (mapped if dual-stack) and identifiers (ports) of a connected socket.
292pub type ConnInfoAddr<A, RI> = ConnIpAddrInner<SpecifiedAddr<A>, NonZeroU16, RI>;
293
294impl<A: IpAddress, LI: Into<NonZeroU16>, RI> From<ConnIpAddr<A, LI, RI>> for ConnInfoAddr<A, RI> {
295    fn from(
296        ConnIpAddr { local: (local_ip, local_identifier), remote: (remote_ip, remote_identifier) }: ConnIpAddr<A, LI, RI>,
297    ) -> Self {
298        Self {
299            local: (local_ip.into(), local_identifier.into()),
300            remote: (remote_ip.into(), remote_identifier),
301        }
302    }
303}
304
305/// The address of a connected socket.
306#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
307#[generic_over_ip()]
308pub struct ConnAddr<A, D> {
309    /// The IP address for the connected socket.
310    pub ip: A,
311    /// The bound device for the connected socket.
312    pub device: Option<D>,
313}
314
315/// The IP address and identifier (port) of a dual-stack listening socket.
316#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
317pub enum DualStackListenerIpAddr<A: IpAddress, LI: Into<NonZeroU16>>
318where
319    A::Version: DualStackIpExt,
320{
321    /// The socket is bound to this stack.
322    ThisStack(ListenerIpAddr<A, LI>),
323    /// The socket is bound to the other stack.
324    OtherStack(ListenerIpAddr<<<A::Version as DualStackIpExt>::OtherVersion as Ip>::Addr, LI>),
325    /// The socket is dual-stack enabled and bound to the IPv6 any address.
326    BothStacks(LI),
327}
328
329impl<A: IpAddress, NewIp: DualStackIpExt, LI: Into<NonZeroU16>> GenericOverIp<NewIp>
330    for DualStackListenerIpAddr<A, LI>
331where
332    A::Version: DualStackIpExt,
333{
334    type Type = DualStackListenerIpAddr<NewIp::Addr, LI>;
335}
336
337impl<LI: Into<NonZeroU16>> Into<(Option<SpecifiedAddr<Ipv6Addr>>, NonZeroU16)>
338    for DualStackListenerIpAddr<Ipv6Addr, LI>
339{
340    fn into(self) -> (Option<SpecifiedAddr<Ipv6Addr>>, NonZeroU16) {
341        match self {
342            Self::ThisStack(listener_ip_addr) => listener_ip_addr.into(),
343            Self::OtherStack(ListenerIpAddr { addr, identifier }) => (
344                Some(addr.map_or(Ipv4::UNSPECIFIED_ADDRESS, SocketIpAddr::addr).to_ipv6_mapped()),
345                identifier.into(),
346            ),
347            Self::BothStacks(identifier) => (None, identifier.into()),
348        }
349    }
350}
351
352/// The IP address and identifiers (ports) of a dual-stack connected socket.
353#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
354#[allow(missing_docs)]
355pub enum DualStackConnIpAddr<A: IpAddress, LI, RI>
356where
357    A::Version: DualStackIpExt,
358{
359    ThisStack(ConnIpAddr<A, LI, RI>),
360    OtherStack(ConnIpAddr<<<A::Version as DualStackIpExt>::OtherVersion as Ip>::Addr, LI, RI>),
361}
362
363impl<A: IpAddress, NewIp: DualStackIpExt, LI, RI> GenericOverIp<NewIp>
364    for DualStackConnIpAddr<A, LI, RI>
365where
366    A::Version: DualStackIpExt,
367{
368    type Type = DualStackConnIpAddr<NewIp::Addr, LI, RI>;
369}
370
371impl<LI: Into<NonZeroU16>, RI> From<DualStackConnIpAddr<Ipv6Addr, LI, RI>>
372    for ConnInfoAddr<Ipv6Addr, RI>
373{
374    fn from(addr: DualStackConnIpAddr<Ipv6Addr, LI, RI>) -> Self {
375        match addr {
376            DualStackConnIpAddr::ThisStack(conn_ip_addr) => conn_ip_addr.into(),
377            DualStackConnIpAddr::OtherStack(ConnIpAddr {
378                local: (local_ip, local_identifier),
379                remote: (remote_ip, remote_identifier),
380            }) => ConnInfoAddr {
381                local: (local_ip.addr().to_ipv6_mapped(), local_identifier.into()),
382                remote: (remote_ip.addr().to_ipv6_mapped(), remote_identifier),
383            },
384        }
385    }
386}
387
388impl<I: Ip, A: SocketMapAddrSpec> From<ListenerIpAddr<I::Addr, A::LocalIdentifier>>
389    for IpAddrVec<I, A>
390{
391    fn from(listener: ListenerIpAddr<I::Addr, A::LocalIdentifier>) -> Self {
392        IpAddrVec::Listener(listener)
393    }
394}
395
396impl<I: Ip, A: SocketMapAddrSpec> From<ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>>
397    for IpAddrVec<I, A>
398{
399    fn from(conn: ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>) -> Self {
400        IpAddrVec::Connected(conn)
401    }
402}
403
404impl<I: Ip, D, A: SocketMapAddrSpec>
405    From<ListenerAddr<ListenerIpAddr<I::Addr, A::LocalIdentifier>, D>> for AddrVec<I, D, A>
406{
407    fn from(listener: ListenerAddr<ListenerIpAddr<I::Addr, A::LocalIdentifier>, D>) -> Self {
408        AddrVec::Listen(listener)
409    }
410}
411
412impl<I: Ip, D, A: SocketMapAddrSpec>
413    From<ConnAddr<ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>, D>>
414    for AddrVec<I, D, A>
415{
416    fn from(
417        conn: ConnAddr<ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>, D>,
418    ) -> Self {
419        AddrVec::Conn(conn)
420    }
421}
422
423/// An address vector containing the portions of a socket address that are
424/// visible in an IP packet.
425#[derive(Derivative)]
426#[derivative(
427    Debug(bound = ""),
428    Clone(bound = ""),
429    Eq(bound = ""),
430    PartialEq(bound = ""),
431    Hash(bound = "")
432)]
433#[allow(missing_docs)]
434pub enum IpAddrVec<I: Ip, A: SocketMapAddrSpec> {
435    Listener(ListenerIpAddr<I::Addr, A::LocalIdentifier>),
436    Connected(ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>),
437}
438
439impl<I: Ip, A: SocketMapAddrSpec> IpAddrVec<I, A> {
440    fn with_device<D>(self, device: Option<D>) -> AddrVec<I, D, A> {
441        match self {
442            IpAddrVec::Listener(ip) => AddrVec::Listen(ListenerAddr { ip, device }),
443            IpAddrVec::Connected(ip) => AddrVec::Conn(ConnAddr { ip, device }),
444        }
445    }
446}
447
448impl<I: Ip, A: SocketMapAddrSpec> IpAddrVec<I, A> {
449    /// Returns the next smallest address vector that would receive all the same
450    /// packets as this one.
451    ///
452    /// Address vectors are ordered by their shadowing relationship, such that
453    /// a "smaller" vector shadows a "larger" one. This function returns the
454    /// smallest of the set of shadows of `self`.
455    fn widen(self) -> Option<Self> {
456        match self {
457            IpAddrVec::Listener(ListenerIpAddr { addr: None, identifier }) => {
458                let _: A::LocalIdentifier = identifier;
459                None
460            }
461            IpAddrVec::Connected(ConnIpAddr { local: (local_ip, local_identifier), remote }) => {
462                let _: (SocketIpAddr<I::Addr>, A::RemoteIdentifier) = remote;
463                Some(ListenerIpAddr { addr: Some(local_ip), identifier: local_identifier })
464            }
465            IpAddrVec::Listener(ListenerIpAddr { addr: Some(addr), identifier }) => {
466                let _: SocketIpAddr<I::Addr> = addr;
467                Some(ListenerIpAddr { addr: None, identifier })
468            }
469        }
470        .map(IpAddrVec::Listener)
471    }
472}
473
474pub(crate) enum AddrVecIterInner<I: Ip, D, A: SocketMapAddrSpec> {
475    WithDevice { device: D, emitted_device: bool, addr: IpAddrVec<I, A> },
476    NoDevice { addr: IpAddrVec<I, A> },
477    Done,
478}
479
480impl<I: Ip, D: Clone, A: SocketMapAddrSpec> Iterator for AddrVecIterInner<I, D, A> {
481    type Item = AddrVec<I, D, A>;
482
483    fn next(&mut self) -> Option<Self::Item> {
484        match self {
485            Self::Done => None,
486            Self::WithDevice { device, emitted_device, addr } => {
487                if !*emitted_device {
488                    *emitted_device = true;
489                    Some(addr.clone().with_device(Some(device.clone())))
490                } else {
491                    let r = addr.clone().with_device(None);
492                    if let Some(next) = addr.clone().widen() {
493                        *addr = next;
494                        *emitted_device = false;
495                    } else {
496                        *self = Self::Done;
497                    }
498                    Some(r)
499                }
500            }
501            Self::NoDevice { addr } => {
502                let r = addr.clone().with_device(None);
503                if let Some(next) = addr.clone().widen() {
504                    *addr = next;
505                } else {
506                    *self = Self::Done
507                }
508                Some(r)
509            }
510        }
511    }
512}
513
514/// An iterator over socket addresses.
515///
516/// The generated address vectors are ordered according to the following
517/// rules (ordered by precedence):
518///   - a connected address is preferred over a listening address,
519///   - a listening address for a specific IP address is preferred over one
520///     for all addresses,
521///   - an address with a specific device is preferred over one for all
522///     devices.
523///
524/// The first yielded address is always the one provided via
525/// [`AddrVecIter::with_device`] or [`AddrVecIter::without_device`].
526pub struct AddrVecIter<I: Ip, D, A: SocketMapAddrSpec>(AddrVecIterInner<I, D, A>);
527
528impl<I: Ip, D, A: SocketMapAddrSpec> AddrVecIter<I, D, A> {
529    /// Constructs an [`AddrVecIter`] with `addr` and a specified `device`.
530    pub fn with_device(addr: IpAddrVec<I, A>, device: D) -> Self {
531        Self(AddrVecIterInner::WithDevice { device, emitted_device: false, addr })
532    }
533
534    /// Constructs an [`AddrVecIter`] with `addr` without a specified device.
535    pub fn without_device(addr: IpAddrVec<I, A>) -> Self {
536        Self(AddrVecIterInner::NoDevice { addr })
537    }
538}
539
540impl<I: Ip, D: Clone, A: SocketMapAddrSpec> Iterator for AddrVecIter<I, D, A> {
541    type Item = AddrVec<I, D, A>;
542
543    fn next(&mut self) -> Option<Self::Item> {
544        let Self(it) = self;
545        it.next()
546    }
547}
548
549#[derive(GenericOverIp)]
550#[generic_over_ip(I, Ip)]
551enum TryUnmapResult<I: DualStackIpExt, D> {
552    /// The address does not have an un-mapped representation.
553    ///
554    /// This spits back the input address unmodified.
555    CannotBeUnmapped(ZonedAddr<SocketIpAddr<I::Addr>, D>),
556    /// The address in the other stack that corresponds to the input.
557    ///
558    /// Since [`SocketIpAddr`] is guaranteed to hold a specified address,
559    /// this must hold an `Option<SocketIpAddr>`. Since `::FFFF:0.0.0.0` is
560    /// a legal IPv4-mapped IPv6 address, this allows us to represent it as the
561    /// unspecified IPv4 address.
562    Mapped(Option<ZonedAddr<SocketIpAddr<<I::OtherVersion as Ip>::Addr>, D>>),
563}
564
565/// Try to convert a specified address into the address that maps to it from
566/// the other stack.
567///
568/// This is an IP-generic function that tries to invert the
569/// IPv4-to-IPv4-mapped-IPv6 conversion that is performed by
570/// [`Ipv4Addr::to_ipv6_mapped`].
571///
572/// The only inputs that will produce [`TryUnmapResult::Mapped`] are
573/// IPv4-mapped IPv6 addresses. All other inputs will produce
574/// [`TryUnmapResult::CannotBeUnmapped`].
575fn try_unmap<A: IpAddress, D>(addr: ZonedAddr<SpecifiedAddr<A>, D>) -> TryUnmapResult<A::Version, D>
576where
577    A::Version: DualStackIpExt,
578{
579    <A::Version as Ip>::map_ip(
580        addr,
581        |v4| {
582            let addr = SocketIpAddr::new_ipv4_specified(v4.addr());
583            TryUnmapResult::CannotBeUnmapped(ZonedAddr::Unzoned(addr))
584        },
585        |v6| match v6.addr().to_ipv4_mapped() {
586            Some(v4) => {
587                let addr = SpecifiedAddr::new(v4).map(SocketIpAddr::new_ipv4_specified);
588                TryUnmapResult::Mapped(addr.map(ZonedAddr::Unzoned))
589            }
590            None => {
591                let (addr, zone) = v6.into_addr_zone();
592                let addr: SocketIpAddr<_> =
593                    addr.try_into().unwrap_or_else(|AddrIsMappedError {}| {
594                        unreachable!(
595                            "addr cannot be mapped because `to_ipv4_mapped` returned `None`"
596                        )
597                    });
598                TryUnmapResult::CannotBeUnmapped(ZonedAddr::new(addr, zone).unwrap_or_else(|| {
599                    unreachable!("addr should still be scopeable after wrapping in `SocketIpAddr`")
600                }))
601            }
602        },
603    )
604}
605
606/// Provides a specified IP address to use in-place of an unspecified
607/// remote.
608///
609/// Concretely, this method is called during `connect()` and `send_to()`
610/// socket operations to transform an unspecified remote IP address to the
611/// loopback address. This ensures conformance with Linux and BSD.
612fn specify_unspecified_remote<I: SocketIpExt, A: From<SocketIpAddr<I::Addr>>, Z>(
613    addr: Option<ZonedAddr<A, Z>>,
614) -> ZonedAddr<A, Z> {
615    addr.unwrap_or_else(|| ZonedAddr::Unzoned(I::LOOPBACK_ADDRESS_AS_SOCKET_IP_ADDR.into()))
616}
617
618/// A remote IP address that's either in the current stack or the other stack.
619#[allow(missing_docs)]
620pub enum DualStackRemoteIp<I: DualStackIpExt, D> {
621    ThisStack(ZonedAddr<SocketIpAddr<I::Addr>, D>),
622    OtherStack(ZonedAddr<SocketIpAddr<<I::OtherVersion as Ip>::Addr>, D>),
623}
624
625impl<I: SocketIpExt + DualStackIpExt<OtherVersion: SocketIpExt>, D> DualStackRemoteIp<I, D> {
626    /// Returns the [`DualStackRemoteIp`] for the given `remote_ip``.
627    ///
628    /// An IPv4-mapped-IPv6 address will be unmapped to the inner IPv4 address,
629    /// and an unspecified address will be populated with
630    /// [`specify_unspecified_remote`].
631    pub fn new(remote_ip: Option<ZonedAddr<SpecifiedAddr<I::Addr>, D>>) -> Self {
632        let remote_ip = specify_unspecified_remote::<I, _, _>(remote_ip);
633        match try_unmap(remote_ip) {
634            TryUnmapResult::CannotBeUnmapped(remote_ip) => Self::ThisStack(remote_ip),
635            TryUnmapResult::Mapped(remote_ip) => {
636                // NB: Even though we ensured the address was specified above by
637                // calling `specify_unspecified_remote`, it's possible that
638                // unmapping the address made it unspecified (e.g. `::FFFF:0.0.0.0`
639                // is a specified IPv6 addr but an unspecified IPv4 addr). Call
640                // `specify_unspecified_remote` again to ensure the unmapped address
641                // is specified.
642                let remote_ip = specify_unspecified_remote::<I::OtherVersion, _, _>(remote_ip);
643                Self::OtherStack(remote_ip)
644            }
645        }
646    }
647}
648
649/// A local IP address that's either in the current stack or the other stack.
650#[allow(missing_docs)]
651pub enum DualStackLocalIp<I: DualStackIpExt, D> {
652    ThisStack(ZonedAddr<SocketIpAddr<I::Addr>, D>),
653    OtherStack(Option<ZonedAddr<SocketIpAddr<<I::OtherVersion as Ip>::Addr>, D>>),
654}
655
656impl<I: SocketIpExt + DualStackIpExt<OtherVersion: SocketIpExt>, D> DualStackLocalIp<I, D> {
657    /// Returns the [`DualStackLocalIp`] for the given `local_ip``.
658    ///
659    /// If `local_ip` is the unspecified address for the other stack, returns
660    /// `Self::OtherStack(None)`.
661    pub fn new(local_ip: ZonedAddr<SpecifiedAddr<I::Addr>, D>) -> Self {
662        match try_unmap(local_ip) {
663            TryUnmapResult::CannotBeUnmapped(local_ip) => Self::ThisStack(local_ip),
664            TryUnmapResult::Mapped(local_ip) => Self::OtherStack(local_ip),
665        }
666    }
667}