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 SocketIpAddr(NonMappedAddr::new_unchecked(SpecifiedAddr::new_unchecked(addr)))
139 }
140
141 pub const unsafe fn new_from_specified_unchecked(addr: SpecifiedAddr<A>) -> SocketIpAddr<A> {
147 SocketIpAddr(NonMappedAddr::new_unchecked(addr))
148 }
149
150 pub fn addr(self) -> A {
152 let SocketIpAddr(addr) = self;
153 **addr
154 }
155
156 pub fn into_inner(self) -> NonMappedAddr<SpecifiedAddr<A>> {
158 let SocketIpAddr(addr) = self;
159 addr
160 }
161
162 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 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 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 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#[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
226impl<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#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
237#[generic_over_ip(A, IpAddress)]
238pub struct ListenerIpAddr<A: IpAddress, LI> {
239 pub addr: Option<SocketIpAddr<A>>,
241 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#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, GenericOverIp)]
256#[generic_over_ip(A, GenericOverIp)]
257pub struct ListenerAddr<A, D> {
258 pub ip: A,
260 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#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
281#[generic_over_ip(A, IpAddress)]
282pub struct ConnIpAddrInner<A, LI, RI> {
283 pub local: (A, LI),
285 pub remote: (A, RI),
287}
288
289pub type ConnIpAddr<A, LI, RI> = ConnIpAddrInner<SocketIpAddr<A>, LI, RI>;
291pub 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#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
307#[generic_over_ip()]
308pub struct ConnAddr<A, D> {
309 pub ip: A,
311 pub device: Option<D>,
313}
314
315#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
317pub enum DualStackListenerIpAddr<A: IpAddress, LI: Into<NonZeroU16>>
318where
319 A::Version: DualStackIpExt,
320{
321 ThisStack(ListenerIpAddr<A, LI>),
323 OtherStack(ListenerIpAddr<<<A::Version as DualStackIpExt>::OtherVersion as Ip>::Addr, LI>),
325 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#[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#[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 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
514pub struct AddrVecIter<I: Ip, D, A: SocketMapAddrSpec>(AddrVecIterInner<I, D, A>);
527
528impl<I: Ip, D, A: SocketMapAddrSpec> AddrVecIter<I, D, A> {
529 pub fn with_device(addr: IpAddrVec<I, A>, device: D) -> Self {
531 Self(AddrVecIterInner::WithDevice { device, emitted_device: false, addr })
532 }
533
534 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 CannotBeUnmapped(ZonedAddr<SocketIpAddr<I::Addr>, D>),
556 Mapped(Option<ZonedAddr<SocketIpAddr<<I::OtherVersion as Ip>::Addr>, D>>),
563}
564
565fn 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
606fn 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#[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 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 let remote_ip = specify_unspecified_remote::<I::OtherVersion, _, _>(remote_ip);
643 Self::OtherStack(remote_ip)
644 }
645 }
646 }
647}
648
649#[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 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}