s2n_quic_core/inet/
ipv4.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::inet::{
5    ip,
6    ipv6::{IpV6Address, SocketAddressV6},
7    unspecified::Unspecified,
8    ExplicitCongestionNotification,
9};
10use core::{fmt, mem::size_of};
11use s2n_codec::zerocopy::U16;
12
13//= https://www.rfc-editor.org/rfc/rfc791#section-2.3
14//# Addresses are fixed length of four octets (32 bits).
15const IPV4_LEN: usize = 32 / 8;
16
17define_inet_type!(
18    pub struct IpV4Address {
19        octets: [u8; IPV4_LEN],
20    }
21);
22
23impl IpV4Address {
24    /// An unspecified IpV4Address
25    pub const UNSPECIFIED: Self = Self {
26        octets: [0; IPV4_LEN],
27    };
28
29    /// Returns the [`ip::UnicastScope`] for the given address
30    ///
31    /// See the [IANA Registry](https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml)
32    /// for more details.
33    ///
34    /// ```
35    /// use s2n_quic_core::inet::{IpV4Address, ip::UnicastScope::*};
36    ///
37    /// assert_eq!(IpV4Address::from([0, 0, 0, 0]).unicast_scope(), None);
38    /// assert_eq!(IpV4Address::from([127, 0, 0, 1]).unicast_scope(), Some(Loopback));
39    /// assert_eq!(IpV4Address::from([127, 1, 1, 1]).unicast_scope(), Some(Loopback));
40    /// assert_eq!(IpV4Address::from([10, 0, 0, 1]).unicast_scope(), Some(Private));
41    /// assert_eq!(IpV4Address::from([100, 64, 0, 1]).unicast_scope(), Some(Private));
42    /// assert_eq!(IpV4Address::from([169, 254, 1, 2]).unicast_scope(), Some(LinkLocal));
43    /// assert_eq!(IpV4Address::from([192, 0, 0, 1]).unicast_scope(), None);
44    /// assert_eq!(IpV4Address::from([192, 0, 0, 9]).unicast_scope(), Some(Global));
45    /// assert_eq!(IpV4Address::from([192, 0, 0, 10]).unicast_scope(), Some(Global));
46    /// assert_eq!(IpV4Address::from([192, 0, 2, 1]).unicast_scope(), None);
47    /// assert_eq!(IpV4Address::from([198, 18, 0, 0]).unicast_scope(), None);
48    /// assert_eq!(IpV4Address::from([198, 19, 1, 1]).unicast_scope(), None);
49    /// assert_eq!(IpV4Address::from([233, 252, 0, 1]).unicast_scope(), None);
50    /// assert_eq!(IpV4Address::from([240, 255, 255, 255]).unicast_scope(), None);
51    /// assert_eq!(IpV4Address::from([255, 255, 255, 255]).unicast_scope(), None);
52    /// assert_eq!(IpV4Address::from([92, 88, 99, 123]).unicast_scope(), Some(Global));
53    /// assert_eq!(IpV4Address::from([168, 254, 169, 253]).unicast_scope(), Some(Global));
54    /// assert_eq!(IpV4Address::from([224, 0, 0, 1]).unicast_scope(), Some(Global));
55    /// ```
56    #[inline]
57    pub const fn unicast_scope(self) -> Option<ip::UnicastScope> {
58        use ip::UnicastScope::*;
59
60        // https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
61        //
62        // NOTE: Even though 192.88.99.0/24 is reserved for "6to4 Relay Anycast", it has been
63        //       deprecated so this code considers it as `Global`.
64        match self.octets {
65            // NOTE: this RFC doesn't quite follow modern formatting so it doesn't parse with the
66            // compliance tool
67            // https://www.rfc-editor.org/rfc/rfc1122#section-3.2.1.3
68            // (a)  { 0, 0 }
69            //
70            //     This host on this network.  MUST NOT be sent, except as
71            //     a source address as part of an initialization procedure
72            //     by which the host learns its own IP address.
73            //
74            //     See also Section 3.3.6 for a non-standard use of {0,0}.
75            [0, 0, 0, 0] => None,
76
77            // (b)  { 0, <Host-number> }
78            //
79            //     Specified host on this network.  It MUST NOT be sent,
80            //     except as a source address as part of an initialization
81            //     procedure by which the host learns its full IP address.
82            [0, _, _, _] => None,
83
84            // NOTE: this RFC doesn't quite follow modern formatting so it doesn't parse with the
85            // compliance tool
86            // https://www.rfc-editor.org/rfc/rfc1122#section-3.2.1.3
87            // (g)  { 127, <any> }
88            //
89            //   Internal host loopback address.  Addresses of this form
90            //   MUST NOT appear outside a host.
91            [127, _, _, _] => Some(Loopback),
92
93            //= https://www.rfc-editor.org/rfc/rfc1918#section-3
94            //# The Internet Assigned Numbers Authority (IANA) has reserved the
95            //# following three blocks of the IP address space for private internets:
96            //#
97            //# 10.0.0.0        -   10.255.255.255  (10/8 prefix)
98            //# 172.16.0.0      -   172.31.255.255  (172.16/12 prefix)
99            //# 192.168.0.0     -   192.168.255.255 (192.168/16 prefix)
100            [10, _, _, _] => Some(Private),
101            [172, 16..=31, _, _] => Some(Private),
102            [192, 168, _, _] => Some(Private),
103
104            //= https://www.rfc-editor.org/rfc/rfc6598#section-7
105            //# The Shared Address Space address range is 100.64.0.0/10.
106            [100, 64..=127, _, _] => {
107                //= https://www.rfc-editor.org/rfc/rfc6598#section-1
108                //# Shared Address Space is similar to [RFC1918] private address space in
109                //# that it is not globally routable address space and can be used by
110                //# multiple pieces of equipment.
111                Some(Private)
112            }
113
114            //= https://www.rfc-editor.org/rfc/rfc3927#section-8
115            //# The IANA has allocated the prefix 169.254/16 for the use described in
116            //# this document.
117            [169, 254, _, _] => Some(LinkLocal),
118
119            //= https://www.rfc-editor.org/rfc/rfc7723#section-4.1
120            //# +----------------------+-------------------------------------------+
121            //# | Attribute            | Value                                     |
122            //# +----------------------+-------------------------------------------+
123            //# | Address Block        | 192.0.0.9/32                              |
124            //# | Name                 | Port Control Protocol Anycast             |
125            //# | RFC                  | RFC 7723 (this document)                  |
126            //# | Allocation Date      | October 2015                              |
127            //# | Termination Date     | N/A                                       |
128            //# | Source               | True                                      |
129            //# | Destination          | True                                      |
130            //# | Forwardable          | True                                      |
131            //# | Global               | True                                      |
132            [192, 0, 0, 9] => Some(Global),
133
134            //= https://www.rfc-editor.org/rfc/rfc8155#section-8.1
135            //# +----------------------+-------------------------------------------+
136            //# | Attribute            | Value                                     |
137            //# +----------------------+-------------------------------------------+
138            //# | Address Block        | 192.0.0.10/32                             |
139            //# | Name                 | Traversal Using Relays around NAT Anycast |
140            //# | RFC                  | RFC 8155                                  |
141            //# | Allocation Date      | 2017-02                                   |
142            //# | Termination Date     | N/A                                       |
143            //# | Source               | True                                      |
144            //# | Destination          | True                                      |
145            //# | Forwardable          | True                                      |
146            //# | Global               | True                                      |
147            [192, 0, 0, 10] => Some(Global),
148
149            //= https://www.rfc-editor.org/rfc/rfc6890#section-2.1
150            //# Table 7 of this document records the assignment of an IPv4 address
151            //# block (192.0.0.0/24) to IANA for IETF protocol assignments.
152            [192, 0, 0, _] => None,
153
154            //= https://www.rfc-editor.org/rfc/rfc2544#C.2.2
155            //# The network addresses 192.18.0.0 through 198.19.255.255 are have been
156            //# assigned to the BMWG by the IANA for this purpose.
157            // NOTE: this range should be 198.18.0.0/15 as corrected by https://www.rfc-editor.org/errata/eid423
158            [198, 18..=19, _, _] => None,
159
160            //= https://www.rfc-editor.org/rfc/rfc5737#section-3
161            //# The blocks 192.0.2.0/24 (TEST-NET-1), 198.51.100.0/24 (TEST-NET-2),
162            //# and 203.0.113.0/24 (TEST-NET-3) are provided for use in
163            //# documentation.
164            [192, 0, 2, _] => None,
165            [198, 51, 100, _] => None,
166            [203, 0, 113, _] => None,
167
168            //= https://www.rfc-editor.org/rfc/rfc6676#section-2
169            //# For Any-Source Multicast (ASM), the IPv4 multicast addresses
170            //# allocated for documentation purposes are 233.252.0.0 - 233.252.0.255
171            //# (233.252.0.0/24).
172            [233, 252, 0, _] => None,
173
174            //= https://www.rfc-editor.org/rfc/rfc1112#section-4
175            //# Class E IP addresses, i.e.,
176            //# those with "1111" as their high-order four bits, are reserved for
177            //# future addressing modes.
178
179            //= https://www.rfc-editor.org/rfc/rfc919#section-7
180            //# The address 255.255.255.255 denotes a broadcast on a local hardware
181            //# network, which must not be forwarded.
182            [240..=255, _, _, _] => None,
183
184            // everything else is considered global
185            _ => Some(Global),
186        }
187    }
188
189    /// Converts the IP address into a IPv6 mapped address
190    #[inline]
191    pub const fn to_ipv6_mapped(self) -> IpV6Address {
192        //= https://www.rfc-editor.org/rfc/rfc5156#section-2.2
193        //# ::FFFF:0:0/96 are the IPv4-mapped addresses [RFC4291].
194        let mut addr = [0; size_of::<IpV6Address>()];
195        let [a, b, c, d] = self.octets;
196        addr[10] = 0xFF;
197        addr[11] = 0xFF;
198        addr[12] = a;
199        addr[13] = b;
200        addr[14] = c;
201        addr[15] = d;
202        IpV6Address { octets: addr }
203    }
204
205    #[inline]
206    pub fn with_port(self, port: u16) -> SocketAddressV4 {
207        SocketAddressV4 {
208            ip: self,
209            port: port.into(),
210        }
211    }
212}
213
214impl fmt::Debug for IpV4Address {
215    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
216        write!(fmt, "IPv4Address({self})")
217    }
218}
219
220impl fmt::Display for IpV4Address {
221    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
222        let octets = &self.octets;
223        write!(
224            fmt,
225            "{}.{}.{}.{}",
226            octets[0], octets[1], octets[2], octets[3]
227        )
228    }
229}
230
231impl Unspecified for IpV4Address {
232    #[inline]
233    fn is_unspecified(&self) -> bool {
234        Self::UNSPECIFIED.eq(self)
235    }
236}
237
238test_inet_snapshot!(ipv4, ipv4_snapshot_test, IpV4Address);
239
240define_inet_type!(
241    pub struct SocketAddressV4 {
242        ip: IpV4Address,
243        port: U16,
244    }
245);
246
247impl SocketAddressV4 {
248    pub const UNSPECIFIED: Self = Self {
249        ip: IpV4Address::UNSPECIFIED,
250        port: U16::ZERO,
251    };
252
253    #[inline]
254    pub const fn ip(&self) -> &IpV4Address {
255        &self.ip
256    }
257
258    #[inline]
259    pub fn port(self) -> u16 {
260        self.port.into()
261    }
262
263    #[inline]
264    pub fn set_port(&mut self, port: u16) {
265        self.port.set(port)
266    }
267
268    #[inline]
269    pub const fn unicast_scope(&self) -> Option<ip::UnicastScope> {
270        self.ip.unicast_scope()
271    }
272
273    /// Converts the IP address into a IPv6 mapped address
274    #[inline]
275    pub const fn to_ipv6_mapped(self) -> SocketAddressV6 {
276        let ip = self.ip().to_ipv6_mapped();
277        let port = self.port;
278        SocketAddressV6 { ip, port }
279    }
280}
281
282impl fmt::Debug for SocketAddressV4 {
283    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
284        write!(fmt, "SocketAddressV4({self})")
285    }
286}
287
288impl fmt::Display for SocketAddressV4 {
289    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
290        write!(fmt, "{}:{}", self.ip, self.port)
291    }
292}
293
294impl Unspecified for SocketAddressV4 {
295    #[inline]
296    fn is_unspecified(&self) -> bool {
297        Self::UNSPECIFIED.eq(self)
298    }
299}
300
301test_inet_snapshot!(socket_v4, socket_v4_snapshot_test, SocketAddressV4);
302
303impl From<[u8; IPV4_LEN]> for IpV4Address {
304    #[inline]
305    fn from(octets: [u8; IPV4_LEN]) -> Self {
306        Self { octets }
307    }
308}
309
310impl From<IpV4Address> for [u8; IPV4_LEN] {
311    #[inline]
312    fn from(address: IpV4Address) -> Self {
313        address.octets
314    }
315}
316
317//= https://www.rfc-editor.org/rfc/rfc791.html#section-3.1
318//#  A summary of the contents of the internet header follows:
319//#
320//#
321//#    0                   1                   2                   3
322//#    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
323//#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
324//#   |Version|  IHL  |Type of Service|          Total Length         |
325//#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
326//#   |         Identification        |Flags|      Fragment Offset    |
327//#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
328//#   |  Time to Live |    Protocol   |         Header Checksum       |
329//#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
330//#   |                       Source Address                          |
331//#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
332//#   |                    Destination Address                        |
333//#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
334//#   |                    Options                    |    Padding    |
335//#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
336
337// Note that Options and Padding are variable length depending on the IHL field
338// so they can't be included directly in the fixed-sized struct.
339define_inet_type!(
340    pub struct Header {
341        vihl: Vihl,
342        tos: Tos,
343        total_len: U16,
344        id: U16,
345        flag_fragment: FlagFragment,
346        ttl: u8,
347        protocol: ip::Protocol,
348        checksum: U16,
349        source: IpV4Address,
350        destination: IpV4Address,
351    }
352);
353
354impl fmt::Debug for Header {
355    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
356        f.debug_struct("ipv4::Header")
357            .field("version", &self.vihl.version())
358            .field("header_len", &self.vihl.header_len())
359            .field("dscp", &self.tos.dscp())
360            .field("ecn", &self.tos.ecn())
361            .field("total_len", &self.total_len)
362            .field("id", &format_args!("0x{:04x}", self.id.get()))
363            .field("flags (reserved)", &self.flag_fragment.reserved())
364            .field(
365                "flags (don't fragment)",
366                &self.flag_fragment.dont_fragment(),
367            )
368            .field(
369                "flags (more fragments)",
370                &self.flag_fragment.more_fragments(),
371            )
372            .field("fragment_offset", &self.flag_fragment.fragment_offset())
373            .field("ttl", &self.ttl)
374            .field("protocol", &self.protocol)
375            .field("checksum", &format_args!("0x{:04x}", self.checksum.get()))
376            .field("source", &self.source)
377            .field("destination", &self.destination)
378            .finish()
379    }
380}
381
382impl Header {
383    /// Swaps the direction of the header
384    #[inline]
385    pub fn swap(&mut self) {
386        core::mem::swap(&mut self.source, &mut self.destination)
387    }
388
389    #[inline]
390    pub const fn vihl(&self) -> &Vihl {
391        &self.vihl
392    }
393
394    #[inline]
395    pub fn vihl_mut(&mut self) -> &mut Vihl {
396        &mut self.vihl
397    }
398
399    #[inline]
400    pub const fn tos(&self) -> &Tos {
401        &self.tos
402    }
403
404    #[inline]
405    pub fn tos_mut(&mut self) -> &mut Tos {
406        &mut self.tos
407    }
408
409    #[inline]
410    pub const fn total_len(&self) -> &U16 {
411        &self.total_len
412    }
413
414    #[inline]
415    pub fn total_len_mut(&mut self) -> &mut U16 {
416        &mut self.total_len
417    }
418
419    #[inline]
420    pub const fn id(&self) -> &U16 {
421        &self.id
422    }
423
424    #[inline]
425    pub fn id_mut(&mut self) -> &mut U16 {
426        &mut self.id
427    }
428
429    #[inline]
430    pub const fn flag_fragment(&self) -> &FlagFragment {
431        &self.flag_fragment
432    }
433
434    #[inline]
435    pub fn flag_fragment_mut(&mut self) -> &mut FlagFragment {
436        &mut self.flag_fragment
437    }
438
439    #[inline]
440    pub const fn ttl(&self) -> &u8 {
441        &self.ttl
442    }
443
444    #[inline]
445    pub fn ttl_mut(&mut self) -> &mut u8 {
446        &mut self.ttl
447    }
448
449    #[inline]
450    pub const fn protocol(&self) -> &ip::Protocol {
451        &self.protocol
452    }
453
454    #[inline]
455    pub fn protocol_mut(&mut self) -> &mut ip::Protocol {
456        &mut self.protocol
457    }
458
459    #[inline]
460    pub const fn checksum(&self) -> &U16 {
461        &self.checksum
462    }
463
464    #[inline]
465    pub fn checksum_mut(&mut self) -> &mut U16 {
466        &mut self.checksum
467    }
468
469    #[inline]
470    pub const fn source(&self) -> &IpV4Address {
471        &self.source
472    }
473
474    #[inline]
475    pub fn source_mut(&mut self) -> &mut IpV4Address {
476        &mut self.source
477    }
478
479    #[inline]
480    pub const fn destination(&self) -> &IpV4Address {
481        &self.destination
482    }
483
484    #[inline]
485    pub fn destination_mut(&mut self) -> &mut IpV4Address {
486        &mut self.destination
487    }
488
489    #[inline]
490    pub fn update_checksum(&mut self) {
491        use core::hash::Hasher;
492
493        self.checksum.set(0);
494
495        let bytes = self.as_bytes();
496
497        let mut checksum = crate::inet::checksum::Checksum::generic();
498
499        checksum.write(bytes);
500
501        self.checksum.set_be(checksum.finish_be());
502    }
503}
504
505// This struct covers the bits for version and IHL (header len).
506//
507// Rust doesn't have the ability to do arbitrary bit sized values so we have to round up to the
508// nearest byte.
509define_inet_type!(
510    pub struct Vihl {
511        value: u8,
512    }
513);
514
515impl fmt::Debug for Vihl {
516    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
517        f.debug_struct("Vihl")
518            .field("version", &self.version())
519            .field("header_len", &self.header_len())
520            .finish()
521    }
522}
523
524impl Vihl {
525    #[inline]
526    pub fn version(&self) -> u8 {
527        self.value >> 4
528    }
529
530    #[inline]
531    pub fn set_version(&mut self, value: u8) -> &mut Self {
532        self.value = (value << 4) | (self.value & 0x0F);
533        self
534    }
535
536    #[inline]
537    pub fn header_len(&self) -> u8 {
538        self.value & 0x0F
539    }
540
541    #[inline]
542    pub fn set_header_len(&mut self, value: u8) -> &mut Self {
543        self.value = (self.value & 0xF0) | (value & 0x0F);
544        self
545    }
546}
547
548// This struct covers the bits for DSCP and ECN.
549//
550// Rust doesn't have the ability to do arbitrary bit sized values so we have to round up to the
551// nearest byte.
552define_inet_type!(
553    pub struct Tos {
554        value: u8,
555    }
556);
557
558impl Tos {
559    /// Differentiated Services Code Point
560    #[inline]
561    pub fn dscp(&self) -> u8 {
562        self.value >> 2
563    }
564
565    #[inline]
566    pub fn set_dscp(&mut self, value: u8) -> &mut Self {
567        self.value = (value << 2) | (self.value & 0b11);
568        self
569    }
570
571    #[inline]
572    pub fn ecn(&self) -> ExplicitCongestionNotification {
573        ExplicitCongestionNotification::new(self.value & 0b11)
574    }
575
576    #[inline]
577    pub fn set_ecn(&mut self, ecn: ExplicitCongestionNotification) -> &mut Self {
578        self.value = (self.value & !0b11) | ecn as u8;
579        self
580    }
581}
582
583impl fmt::Debug for Tos {
584    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
585        f.debug_struct("ipv4::Tos")
586            .field("dscp", &self.dscp())
587            .field("ecn", &self.ecn())
588            .finish()
589    }
590}
591
592// This struct covers the bits for Flags and Fragment Offset.
593//
594// Rust doesn't have the ability to do arbitrary bit sized values so we have to round up to the
595// nearest byte.
596define_inet_type!(
597    pub struct FlagFragment {
598        value: U16,
599    }
600);
601
602impl FlagFragment {
603    const FRAGMENT_MASK: u16 = 0b0001_1111_1111_1111;
604
605    #[inline]
606    pub fn reserved(&self) -> bool {
607        self.get(1 << 15)
608    }
609
610    pub fn set_reserved(&mut self, enabled: bool) -> &mut Self {
611        self.set(1 << 15, enabled)
612    }
613
614    #[inline]
615    pub fn dont_fragment(&self) -> bool {
616        self.get(1 << 14)
617    }
618
619    #[inline]
620    pub fn set_dont_fragment(&mut self, enabled: bool) -> &mut Self {
621        self.set(1 << 14, enabled)
622    }
623
624    #[inline]
625    pub fn more_fragments(&self) -> bool {
626        self.get(1 << 13)
627    }
628
629    #[inline]
630    pub fn set_more_fragments(&mut self, enabled: bool) -> &mut Self {
631        self.set(1 << 13, enabled)
632    }
633
634    #[inline]
635    pub fn fragment_offset(&self) -> u16 {
636        self.value.get() & Self::FRAGMENT_MASK
637    }
638
639    #[inline]
640    pub fn set_fragment_offset(&mut self, offset: u16) -> &mut Self {
641        self.value
642            .set(self.value.get() & !Self::FRAGMENT_MASK | offset & Self::FRAGMENT_MASK);
643        self
644    }
645
646    #[inline]
647    fn get(&self, mask: u16) -> bool {
648        self.value.get() & mask == mask
649    }
650
651    #[inline]
652    fn set(&mut self, mask: u16, enabled: bool) -> &mut Self {
653        let value = self.value.get();
654        let value = if enabled { value | mask } else { value & !mask };
655        self.value.set(value);
656        self
657    }
658}
659
660impl fmt::Debug for FlagFragment {
661    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
662        f.debug_struct("ipv4::FlagFragment")
663            .field("reserved", &self.reserved())
664            .field("dont_fragment", &self.dont_fragment())
665            .field("more_fragments", &self.more_fragments())
666            .field("fragment_offset", &self.fragment_offset())
667            .finish()
668    }
669}
670
671#[cfg(any(test, feature = "std"))]
672mod std_conversion {
673    use super::*;
674    use std::net;
675
676    impl From<net::Ipv4Addr> for IpV4Address {
677        fn from(address: net::Ipv4Addr) -> Self {
678            (&address).into()
679        }
680    }
681
682    impl From<&net::Ipv4Addr> for IpV4Address {
683        fn from(address: &net::Ipv4Addr) -> Self {
684            address.octets().into()
685        }
686    }
687
688    impl From<IpV4Address> for net::Ipv4Addr {
689        fn from(address: IpV4Address) -> Self {
690            address.octets.into()
691        }
692    }
693
694    impl From<net::SocketAddrV4> for SocketAddressV4 {
695        fn from(address: net::SocketAddrV4) -> Self {
696            let ip = address.ip().into();
697            let port = address.port().into();
698            Self { ip, port }
699        }
700    }
701
702    impl From<(net::Ipv4Addr, u16)> for SocketAddressV4 {
703        fn from((ip, port): (net::Ipv4Addr, u16)) -> Self {
704            Self::new(ip, port)
705        }
706    }
707
708    impl From<SocketAddressV4> for net::SocketAddrV4 {
709        fn from(address: SocketAddressV4) -> Self {
710            let ip = address.ip.into();
711            let port = address.port.into();
712            Self::new(ip, port)
713        }
714    }
715
716    impl From<&SocketAddressV4> for net::SocketAddrV4 {
717        fn from(address: &SocketAddressV4) -> Self {
718            let ip = address.ip.into();
719            let port = address.port.into();
720            Self::new(ip, port)
721        }
722    }
723
724    impl From<SocketAddressV4> for net::SocketAddr {
725        fn from(address: SocketAddressV4) -> Self {
726            let addr: net::SocketAddrV4 = address.into();
727            addr.into()
728        }
729    }
730
731    impl From<&SocketAddressV4> for net::SocketAddr {
732        fn from(address: &SocketAddressV4) -> Self {
733            let addr: net::SocketAddrV4 = address.into();
734            addr.into()
735        }
736    }
737
738    impl net::ToSocketAddrs for SocketAddressV4 {
739        type Iter = std::iter::Once<net::SocketAddr>;
740
741        fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
742            let ip = self.ip.into();
743            let port = self.port.into();
744            let addr = net::SocketAddrV4::new(ip, port);
745            Ok(std::iter::once(addr.into()))
746        }
747    }
748}
749
750#[cfg(test)]
751mod tests {
752    use super::*;
753    use bolero::{check, generator::*};
754    use s2n_codec::{DecoderBuffer, DecoderBufferMut};
755
756    /// Asserts the Scope returned matches a known implementation
757    #[test]
758    #[cfg_attr(kani, kani::proof, kani::unwind(5), kani::solver(kissat))]
759    fn scope_test() {
760        let g = produce::<[u8; 4]>().map_gen(IpV4Address::from);
761        check!().with_generator(g).cloned().for_each(|subject| {
762            use ip::UnicastScope::*;
763
764            let expected = std::net::Ipv4Addr::from(subject);
765
766            // Several IP methods are blocked behind `feature(ip)`: https://github.com/rust-lang/rust/issues/27709
767            //
768            // Use the `ip_network` crate to fill any gaps
769            let network = ip_network::Ipv4Network::from(expected);
770
771            match subject.unicast_scope() {
772                Some(Global) => {
773                    // ip_network has a bug in the `is_global` logic. Remove this once its fixed
774                    // and published
775                    // https://github.com/JakubOnderka/ip_network/pull/7
776                    if subject.octets == [192, 0, 0, 9] || subject.octets == [192, 0, 0, 10] {
777                        return;
778                    }
779
780                    assert!(network.is_global());
781                }
782                Some(Private) => {
783                    assert!(expected.is_private() || network.is_shared_address_space());
784                }
785                Some(Loopback) => {
786                    assert!(expected.is_loopback());
787                }
788                Some(LinkLocal) => {
789                    assert!(expected.is_link_local());
790                }
791                None => {
792                    assert!(
793                        expected.is_broadcast()
794                            || expected.is_multicast()
795                            || expected.is_documentation()
796                            || network.is_benchmarking()
797                            || network.is_ietf_protocol_assignments()
798                            || network.is_reserved()
799                            || network.is_local_identification()
800                            || network.is_unspecified()
801                    );
802                }
803            }
804        })
805    }
806
807    #[test]
808    #[cfg_attr(miri, ignore)]
809    fn snapshot_test() {
810        let mut buffer = vec![0u8; core::mem::size_of::<Header>()];
811        for (idx, byte) in buffer.iter_mut().enumerate() {
812            *byte = idx as u8;
813        }
814        let decoder = DecoderBuffer::new(&buffer);
815        let (header, _) = decoder.decode::<&Header>().unwrap();
816        insta::assert_debug_snapshot!("snapshot_test", header);
817
818        buffer.fill(255);
819        let decoder = DecoderBuffer::new(&buffer);
820        let (header, _) = decoder.decode::<&Header>().unwrap();
821        insta::assert_debug_snapshot!("snapshot_filled_test", header);
822    }
823
824    #[test]
825    #[cfg_attr(kani, kani::proof, kani::unwind(5), kani::solver(kissat))]
826    fn header_getter_setter_test() {
827        check!().with_type::<Header>().for_each(|expected| {
828            let mut buffer = [255u8; core::mem::size_of::<Header>()];
829            let decoder = DecoderBufferMut::new(&mut buffer);
830            let (header, _) = decoder.decode::<&mut Header>().unwrap();
831            {
832                // use all of the getters and setters to copy over each field
833                header
834                    .vihl_mut()
835                    .set_version(expected.vihl().version())
836                    .set_header_len(expected.vihl().header_len());
837                header
838                    .tos_mut()
839                    .set_dscp(expected.tos().dscp())
840                    .set_ecn(expected.tos().ecn());
841                header.id_mut().set(expected.id().get());
842                header.total_len_mut().set(expected.total_len().get());
843                header
844                    .flag_fragment_mut()
845                    .set_reserved(expected.flag_fragment().reserved())
846                    .set_dont_fragment(expected.flag_fragment().dont_fragment())
847                    .set_more_fragments(expected.flag_fragment().more_fragments())
848                    .set_fragment_offset(expected.flag_fragment().fragment_offset());
849                *header.ttl_mut() = *expected.ttl();
850                *header.protocol_mut() = *expected.protocol();
851                header.checksum_mut().set(expected.checksum().get());
852                *header.source_mut() = *expected.source();
853                *header.destination_mut() = *expected.destination();
854            }
855
856            let decoder = DecoderBuffer::new(&buffer);
857            let (actual, _) = decoder.decode::<&Header>().unwrap();
858            {
859                // make sure all of the values match
860                assert_eq!(expected, actual);
861                assert_eq!(expected.vihl(), actual.vihl());
862                assert_eq!(expected.vihl().version(), actual.vihl().version());
863                assert_eq!(expected.vihl().header_len(), actual.vihl().header_len());
864                assert_eq!(expected.tos(), actual.tos());
865                assert_eq!(expected.tos().dscp(), actual.tos().dscp());
866                assert_eq!(expected.tos().ecn(), actual.tos().ecn());
867                assert_eq!(expected.id(), actual.id());
868                assert_eq!(expected.total_len(), actual.total_len());
869                assert_eq!(expected.flag_fragment(), actual.flag_fragment());
870                assert_eq!(
871                    expected.flag_fragment().reserved(),
872                    actual.flag_fragment().reserved()
873                );
874                assert_eq!(
875                    expected.flag_fragment().dont_fragment(),
876                    actual.flag_fragment().dont_fragment()
877                );
878                assert_eq!(
879                    expected.flag_fragment().more_fragments(),
880                    actual.flag_fragment().more_fragments()
881                );
882                assert_eq!(expected.ttl(), actual.ttl());
883                assert_eq!(expected.protocol(), actual.protocol());
884                assert_eq!(expected.checksum(), actual.checksum());
885                assert_eq!(expected.source(), actual.source());
886                assert_eq!(expected.destination(), actual.destination());
887            }
888        })
889    }
890
891    #[test]
892    fn header_round_trip_test() {
893        check!().for_each(|buffer| {
894            s2n_codec::assert_codec_round_trip_bytes!(Header, buffer);
895        });
896    }
897}