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::{
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#[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 pub fn into_inner(self) -> ZonedAddr<W, Z> {
52 let StrictlyZonedAddr { addr, marker: PhantomData } = self;
53 addr
54 }
55
56 pub fn into_inner_without_witness(self) -> ZonedAddr<A, Z> {
58 self.into_inner().map_addr(|addr| addr.into_addr())
59 }
60
61 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 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#[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 pub fn new(addr: A) -> Option<SocketIpAddr<A>> {
124 Some(SocketIpAddr(NonMappedAddr::new(SpecifiedAddr::new(addr)?)?))
125 }
126
127 pub fn new_from_witness(addr: NonMappedAddr<SpecifiedAddr<A>>) -> Self {
129 Self(addr)
130 }
131
132 pub const unsafe fn new_unchecked(addr: A) -> SocketIpAddr<A> {
140 let non_mapped =
142 unsafe { NonMappedAddr::new_unchecked(SpecifiedAddr::new_unchecked(addr)) };
143 SocketIpAddr(non_mapped)
144 }
145
146 pub const unsafe fn new_from_specified_unchecked(addr: SpecifiedAddr<A>) -> SocketIpAddr<A> {
152 let non_mapped = unsafe { NonMappedAddr::new_unchecked(addr) };
154 SocketIpAddr(non_mapped)
155 }
156
157 pub fn addr(self) -> A {
159 let SocketIpAddr(addr) = self;
160 **addr
161 }
162
163 pub fn into_inner(self) -> NonMappedAddr<SpecifiedAddr<A>> {
165 let SocketIpAddr(addr) = self;
166 addr
167 }
168
169 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 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 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 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 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#[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
243impl<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#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
254#[generic_over_ip(A, IpAddress)]
255pub struct ListenerIpAddr<A: IpAddress, LI> {
256 pub addr: Option<SocketIpAddr<A>>,
258 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#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, GenericOverIp)]
273#[generic_over_ip(A, GenericOverIp)]
274pub struct ListenerAddr<A, D> {
275 pub ip: A,
277 pub device: Option<D>,
279}
280
281impl<A, D> ListenerAddr<A, D>
282where
283 A: Clone,
284{
285 pub fn without_device(&self) -> Self {
287 Self { ip: self.ip.clone(), device: None }
288 }
289
290 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 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 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#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
333#[generic_over_ip(A, IpAddress)]
334pub struct ConnIpAddrInner<A, LI, RI> {
335 pub local: (A, LI),
337 pub remote: (A, RI),
339}
340
341pub type ConnIpAddr<A, LI, RI> = ConnIpAddrInner<SocketIpAddr<A>, LI, RI>;
343pub 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#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
359#[generic_over_ip()]
360pub struct ConnAddr<A, D> {
361 pub ip: A,
363 pub device: Option<D>,
365}
366
367#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
369pub enum DualStackListenerIpAddr<A: IpAddress, LI: Into<NonZeroU16>>
370where
371 A::Version: DualStackIpExt,
372{
373 ThisStack(ListenerIpAddr<A, LI>),
375 OtherStack(ListenerIpAddr<<<A::Version as DualStackIpExt>::OtherVersion as Ip>::Addr, LI>),
377 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#[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#[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 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 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
571pub struct AddrVecIter<I: Ip, D, A: SocketMapAddrSpec>(AddrVecIterInner<I, D, A>);
584
585impl<I: Ip, D, A: SocketMapAddrSpec> AddrVecIter<I, D, A> {
586 pub fn with_device(addr: IpAddrVec<I, A>, device: D) -> Self {
588 Self(AddrVecIterInner::WithDevice { device, emitted_device: false, addr })
589 }
590
591 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 CannotBeUnmapped(ZonedAddr<SocketIpAddr<I::Addr>, D>),
613 Mapped(Option<ZonedAddr<SocketIpAddr<<I::OtherVersion as Ip>::Addr>, D>>),
620}
621
622fn 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
663fn 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#[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 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 let remote_ip = specify_unspecified_remote::<I::OtherVersion, _, _>(remote_ip);
700 Self::OtherStack(remote_ip)
701 }
702 }
703 }
704}
705
706#[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 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}