1use 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
13const IPV4_LEN: usize = 32 / 8;
16
17define_inet_type!(
18 pub struct IpV4Address {
19 octets: [u8; IPV4_LEN],
20 }
21);
22
23impl IpV4Address {
24 pub const UNSPECIFIED: Self = Self {
26 octets: [0; IPV4_LEN],
27 };
28
29 #[inline]
57 pub const fn unicast_scope(self) -> Option<ip::UnicastScope> {
58 use ip::UnicastScope::*;
59
60 match self.octets {
65 [0, 0, 0, 0] => None,
76
77 [0, _, _, _] => None,
83
84 [127, _, _, _] => Some(Loopback),
92
93 [10, _, _, _] => Some(Private),
101 [172, 16..=31, _, _] => Some(Private),
102 [192, 168, _, _] => Some(Private),
103
104 [100, 64..=127, _, _] => {
107 Some(Private)
112 }
113
114 [169, 254, _, _] => Some(LinkLocal),
118
119 [192, 0, 0, 9] => Some(Global),
133
134 [192, 0, 0, 10] => Some(Global),
148
149 [192, 0, 0, _] => None,
153
154 [198, 18..=19, _, _] => None,
159
160 [192, 0, 2, _] => None,
165 [198, 51, 100, _] => None,
166 [203, 0, 113, _] => None,
167
168 [233, 252, 0, _] => None,
173
174 [240..=255, _, _, _] => None,
183
184 _ => Some(Global),
186 }
187 }
188
189 #[inline]
191 pub const fn to_ipv6_mapped(self) -> IpV6Address {
192 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 #[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
317define_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 #[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
505define_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
548define_inet_type!(
553 pub struct Tos {
554 value: u8,
555 }
556);
557
558impl Tos {
559 #[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
592define_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 #[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 let network = ip_network::Ipv4Network::from(expected);
770
771 match subject.unicast_scope() {
772 Some(Global) => {
773 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 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 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}