Skip to main content

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