lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20230814092302.1903203-3-dallerivemichele@gmail.com>
Date:   Mon, 14 Aug 2023 11:22:57 +0200
From:   Michele Dalle Rive <dallerivemichele@...il.com>
To:     Miguel Ojeda <ojeda@...nel.org>,
        Alex Gaynor <alex.gaynor@...il.com>,
        Wedson Almeida Filho <wedsonaf@...il.com>,
        "David S. Miller" <davem@...emloft.net>
Cc:     Eric Dumazet <edumazet@...gle.com>,
        Jakub Kicinski <kuba@...nel.org>,
        Paolo Abeni <pabeni@...hat.com>,
        Boqun Feng <boqun.feng@...il.com>, Gary Guo <gary@...yguo.net>,
        Björn Roy Baron <bjorn3_gh@...tonmail.com>,
        Benno Lossin <benno.lossin@...ton.me>,
        Alice Ryhl <aliceryhl@...gle.com>,
        Davide Rovelli <davide.rovelli@....ch>,
        rust-for-linux@...r.kernel.org, netdev@...r.kernel.org,
        linux-kernel@...r.kernel.org, patches@...ts.linux.dev,
        Michele Dalle Rive <dallerivemichele@...il.com>
Subject: [RFC PATCH 2/7] rust: net: add ip and socket address bindings.

Create structures to handle addresses: `Ipv4Addr`, `Ipv6Addr`,
`SocketAddr`, `SocketAddrV4` and `SocketAddrV6`.

These structures are meant to be as similar as possible to the ones in
Rust `std::net`, while, at the same time, providing functionalities
available in the kernel.

Some extra structures are added, compared to `std`:
- `SocketAddrStorage`: wraps `struct sockaddr_storage` and is used to
  interact with the kernel functions when the type of socket address is
  unknown. Since it is only used for FFI, it is crate-public.
- `GenericSocketAddr`: trait that defines shared functions and traits
  amont all socket addresses.

Signed-off-by: Michele Dalle Rive <dallerivemichele@...il.com>
---
A few questions here:
- Should `SocketAddrStorage` be crate-public or public? My reasoning is
  that modules should be using `SocketAddr` for an "unspecified" socket
  address type; however, having `SocketAddrStorage` available could give
  the freedom of eventually using bindings directly to do more complex
  tasks.
- Is `GenericSocketAddr` useful? I thought it could be convenient
  to have a socket address trait, as a sort of "superclass" for all
  socket addresses. However, I think it has no particular use, since
  there is `SocketAddr`.
- Should the addresses be divided in two files, one for ip addresses and
  one for socket addresses? Or everything together works?

 rust/kernel/net.rs      |    2 +
 rust/kernel/net/addr.rs | 1215 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 1217 insertions(+)
 create mode 100644 rust/kernel/net/addr.rs

diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
index 1eda336b48e4..346e7374e614 100644
--- a/rust/kernel/net.rs
+++ b/rust/kernel/net.rs
@@ -9,6 +9,8 @@
 
 use crate::error::{code, Error};
 use core::cell::UnsafeCell;
+
+pub mod addr;
 pub mod ip;
 
 /// The address family.
diff --git a/rust/kernel/net/addr.rs b/rust/kernel/net/addr.rs
new file mode 100644
index 000000000000..e6b1ba7320db
--- /dev/null
+++ b/rust/kernel/net/addr.rs
@@ -0,0 +1,1215 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Network address types.
+//!
+//! This module contains the types and APIs related to network addresses.
+//! The methods and types of this API are inspired by the [Rust standard library's `std::net` module](https://doc.rust-lang.org/std/net/index.html),
+//! but have been ported to use the kernel's C APIs.
+
+use crate::error::{code, Error, Result};
+use crate::net::{init_net, AddressFamily, Namespace};
+use crate::str::{CStr, CString};
+use crate::{c_str, fmt};
+use core::cmp::Ordering;
+use core::fmt::{Debug, Display, Formatter};
+use core::hash::{Hash, Hasher};
+use core::mem::MaybeUninit;
+use core::ptr;
+use core::str::FromStr;
+
+/// An IPv4 address.
+///
+/// Wraps a `struct in_addr`.
+#[derive(Default, Copy, Clone)]
+#[repr(transparent)]
+pub struct Ipv4Addr(pub(crate) bindings::in_addr);
+
+impl Ipv4Addr {
+    /// The maximum length of an IPv4 address string.
+    ///
+    /// This is the length of the string representation of the address.
+    /// It does not include the null terminator.
+    pub const MAX_STRING_LEN: usize = 15;
+
+    /// Create a new IPv4 address from four 8-bit integers.
+    ///
+    /// The IP address will be `a.b.c.d`.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::new(192, 168, 0, 1);
+    /// ```
+    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
+        Self::from_bits(u32::from_be_bytes([a, b, c, d]))
+    }
+
+    /// Get the octets of the address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::new(192, 168, 0, 1);
+    /// let expected = [192, 168, 0, 1];
+    /// assert_eq!(addr.octets(), &expected);
+    /// ```
+    pub const fn octets(&self) -> &[u8; 4] {
+        // SAFETY: The s_addr field is a 32-bit integer, which is the same size as the array.
+        unsafe { &*(&self.0.s_addr as *const _ as *const [u8; 4]) }
+    }
+
+    /// Create a new IPv4 address from a 32-bit integer.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::from_bits(0xc0a80001);
+    /// assert_eq!(addr, Ipv4Addr::new(192, 168, 0, 1));
+    /// ```
+    pub const fn from_bits(bits: u32) -> Self {
+        Ipv4Addr(bindings::in_addr {
+            s_addr: bits.to_be(),
+        })
+    }
+
+    /// Get the 32-bit integer representation of the address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::new(192, 168, 0, 1);
+    /// assert_eq!(addr.to_bits(), 0xc0a80001);
+    /// ```
+    pub const fn to_bits(&self) -> u32 {
+        u32::from_be(self.0.s_addr)
+    }
+
+    /// The broadcast address: `255.255.255.255`
+    ///
+    /// Used to send a message to all hosts on the network.
+    pub const BROADCAST: Self = Self::new(255, 255, 255, 255);
+
+    /// "None" address
+    ///
+    /// Can be used as return value to indicate an error.
+    pub const NONE: Self = Self::new(255, 255, 255, 255);
+
+    /// The "any" address: `0.0.0.0`
+    /// Used to accept any incoming message.
+    pub const UNSPECIFIED: Self = Self::new(0, 0, 0, 0);
+
+    /// A dummy address: `192.0.0.8`
+    /// Used as ICMP reply source if no address is set.
+    pub const DUMMY: Self = Self::new(192, 0, 0, 8);
+
+    /// The loopback address: `127.0.0.1`
+    /// Used to send a message to the local host.
+    pub const LOOPBACK: Self = Self::new(127, 0, 0, 1);
+}
+
+impl From<[u8; 4]> for Ipv4Addr {
+    /// Create a new IPv4 address from an array of 8-bit integers.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::from([192, 168, 0, 1]);
+    /// assert_eq!(addr, Ipv4Addr::new(192, 168, 0, 1));
+    /// ```
+    fn from(octets: [u8; 4]) -> Self {
+        Self::new(octets[0], octets[1], octets[2], octets[3])
+    }
+}
+
+impl From<Ipv4Addr> for u32 {
+    /// Get the 32-bit integer representation of the address.
+    ///
+    /// This is the same as calling [`Ipv4Addr::to_bits`].
+    fn from(addr: Ipv4Addr) -> Self {
+        addr.to_bits()
+    }
+}
+
+impl From<u32> for Ipv4Addr {
+    /// Create a new IPv4 address from a 32-bit integer.
+    ///
+    /// This is the same as calling [`Ipv4Addr::from_bits`].
+    fn from(bits: u32) -> Self {
+        Self::from_bits(bits)
+    }
+}
+
+impl PartialEq<Ipv4Addr> for Ipv4Addr {
+    /// Compare two IPv4 addresses.
+    ///
+    /// Returns `true` if the addresses are made up of the same bytes.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr1 = Ipv4Addr::new(192, 168, 0, 1);
+    /// let addr2 = Ipv4Addr::new(192, 168, 0, 1);
+    /// assert_eq!(addr1, addr2);
+    ///
+    /// let addr3 = Ipv4Addr::new(192, 168, 0, 2);
+    /// assert_ne!(addr1, addr3);
+    /// ```
+    fn eq(&self, other: &Ipv4Addr) -> bool {
+        self.to_bits() == other.to_bits()
+    }
+}
+
+impl Eq for Ipv4Addr {}
+
+impl Hash for Ipv4Addr {
+    /// Hash an IPv4 address.
+    ///
+    /// The trait cannot be derived because the `in_addr` struct does not implement `Hash`.
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.to_bits().hash(state)
+    }
+}
+
+impl PartialOrd for Ipv4Addr {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.to_bits().partial_cmp(&other.to_bits())
+    }
+}
+
+impl Ord for Ipv4Addr {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.to_bits().cmp(&other.to_bits())
+    }
+}
+
+/// An IPv6 address.
+///
+/// Wraps a `struct in6_addr`.
+#[derive(Default, Copy, Clone)]
+#[repr(transparent)]
+pub struct Ipv6Addr(pub(crate) bindings::in6_addr);
+
+impl Ipv6Addr {
+    /// The maximum length of an IPv6 address string.
+    ///
+    /// This is the length of the string representation of the address.
+    /// It does not include the null terminator.
+    pub const MAX_STRING_LEN: usize = 45;
+
+    /// Create a new IPv6 address from eight 16-bit integers.
+    ///
+    /// The 16-bit integers are transformed in network order.
+    ///
+    /// The IP address will be `a:b:c:d:e:f:g:h`.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334);
+    /// ```
+    #[allow(clippy::too_many_arguments)]
+    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Self {
+        Self(bindings::in6_addr {
+            in6_u: bindings::in6_addr__bindgen_ty_1 {
+                u6_addr16: [
+                    a.to_be(),
+                    b.to_be(),
+                    c.to_be(),
+                    d.to_be(),
+                    e.to_be(),
+                    f.to_be(),
+                    g.to_be(),
+                    h.to_be(),
+                ],
+            },
+        })
+    }
+
+    /// Get the octets of the address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334);
+    /// let expected = [0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34];
+    /// assert_eq!(addr.octets(), &expected);
+    /// ```
+    pub const fn octets(&self) -> &[u8; 16] {
+        // SAFETY: The u6_addr8 field is a [u8; 16] array.
+        unsafe { &self.0.in6_u.u6_addr8 }
+    }
+
+    /// Get the segments of the address.
+    ///
+    /// A segment is a 16-bit integer.
+    /// The segments are in network order.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334);
+    /// let expected = [0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334];
+    /// assert_eq!(addr.segments(), &expected);
+    /// ```
+    pub const fn segments(&self) -> &[u16; 8] {
+        // SAFETY: The u6_addr16 field is a [u16; 8] array.
+        unsafe { &self.0.in6_u.u6_addr16 }
+    }
+
+    /// Create a 128-bit integer representation of the address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334);
+    /// assert_eq!(addr.to_bits(), 0x20010db885a3000000008a2e03707334);
+    /// ```
+    pub fn to_bits(&self) -> u128 {
+        u128::from_be_bytes(*self.octets() as _)
+    }
+
+    /// Create a new IPv6 address from a 128-bit integer.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::from_bits(0x20010db885a3000000008a2e03707334);
+    /// assert_eq!(addr, Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334));
+    /// ```
+    pub const fn from_bits(bits: u128) -> Self {
+        Ipv6Addr(bindings::in6_addr {
+            in6_u: bindings::in6_addr__bindgen_ty_1 {
+                u6_addr8: bits.to_be_bytes() as _,
+            },
+        })
+    }
+
+    /// The "any" address: `::`
+    ///
+    /// Used to accept any incoming message.
+    /// Should not be used as a destination address.
+    pub const ANY: Self = Self::new(0, 0, 0, 0, 0, 0, 0, 0);
+
+    /// The loopback address: `::1`
+    ///
+    /// Used to send a message to the local host.
+    pub const LOOPBACK: Self = Self::new(0, 0, 0, 0, 0, 0, 0, 1);
+}
+
+impl From<[u16; 8]> for Ipv6Addr {
+    fn from(value: [u16; 8]) -> Self {
+        Self(bindings::in6_addr {
+            in6_u: bindings::in6_addr__bindgen_ty_1 { u6_addr16: value },
+        })
+    }
+}
+
+impl From<[u8; 16]> for Ipv6Addr {
+    fn from(value: [u8; 16]) -> Self {
+        Self(bindings::in6_addr {
+            in6_u: bindings::in6_addr__bindgen_ty_1 { u6_addr8: value },
+        })
+    }
+}
+
+impl From<Ipv6Addr> for u128 {
+    fn from(addr: Ipv6Addr) -> Self {
+        addr.to_bits()
+    }
+}
+
+impl From<u128> for Ipv6Addr {
+    fn from(bits: u128) -> Self {
+        Self::from_bits(bits)
+    }
+}
+
+impl PartialEq for Ipv6Addr {
+    fn eq(&self, other: &Self) -> bool {
+        self.to_bits() == other.to_bits()
+    }
+}
+
+impl Eq for Ipv6Addr {}
+
+impl Hash for Ipv6Addr {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.to_bits().hash(state)
+    }
+}
+
+impl PartialOrd for Ipv6Addr {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.to_bits().partial_cmp(&other.to_bits())
+    }
+}
+
+impl Ord for Ipv6Addr {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.to_bits().cmp(&other.to_bits())
+    }
+}
+
+/// A wrapper for a generic socket address.
+///
+/// Wraps a C `struct sockaddr_storage`.
+/// Unlike [`SocketAddr`], this struct is meant to be used internally only,
+/// as a parameter for kernel function calls.
+#[repr(transparent)]
+#[derive(Copy, Clone, Default)]
+pub(crate) struct SocketAddrStorage(pub(crate) bindings::__kernel_sockaddr_storage);
+
+impl SocketAddrStorage {
+    /// Returns the family of the address.
+    pub(crate) fn family(&self) -> Result<AddressFamily, Error> {
+        // SAFETY: The union access is safe because the `ss_family` field is always valid.
+        let val: isize = unsafe { self.0.__bindgen_anon_1.__bindgen_anon_1.ss_family as _ };
+        AddressFamily::try_from(val)
+    }
+
+    pub(crate) fn into<T: GenericSocketAddr>(self) -> T {
+        // SAFETY: The `self.0` field is a `struct sockaddr_storage` which is guaranteed to be large enough to hold any socket address.
+        unsafe { *(&self.0 as *const _ as *const T) }
+    }
+}
+
+/// A generic Socket Address. Acts like a `struct sockaddr_storage`.
+/// `sockaddr_storage` is used instead of `sockaddr` because it is guaranteed to be large enough to hold any socket address.
+///
+/// The purpose of this enum is to be used as a generic parameter for functions that can take any type of address.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum SocketAddr {
+    /// An IPv4 address.
+    V4(SocketAddrV4),
+    /// An IPv6 address.
+    V6(SocketAddrV6),
+}
+
+impl SocketAddr {
+    /// Returns the size in bytes of the concrete address contained.
+    ///
+    /// Used in the kernel functions that take a parameter with the size of the socket address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddr, SocketAddrV4};
+    /// assert_eq!(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 80)).size(),
+    ///           core::mem::size_of::<SocketAddrV4>());
+    pub fn size(&self) -> usize {
+        match self {
+            SocketAddr::V4(_) => SocketAddrV4::size(),
+            SocketAddr::V6(_) => SocketAddrV6::size(),
+        }
+    }
+
+    /// Returns the address family of the concrete address contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddr, SocketAddrV4};
+    /// use kernel::net::AddressFamily;
+    /// assert_eq!(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 80)).family(),
+    ///          AddressFamily::Inet);
+    /// ```
+    pub fn family(&self) -> AddressFamily {
+        match self {
+            SocketAddr::V4(_) => AddressFamily::Inet,
+            SocketAddr::V6(_) => AddressFamily::Inet6,
+        }
+    }
+
+    /// Returns a pointer to the C `struct sockaddr_storage` contained.
+    /// Used in the kernel functions that take a pointer to a socket address.
+    pub(crate) fn as_ptr(&self) -> *const SocketAddrStorage {
+        match self {
+            SocketAddr::V4(addr) => addr as *const _ as _,
+            SocketAddr::V6(addr) => addr as *const _ as _,
+        }
+    }
+
+    /// Creates a `SocketAddr` from a C `struct sockaddr_storage`.
+    /// The function consumes the `struct sockaddr_storage`.
+    /// Used in the kernel functions that return a socket address.
+    ///
+    /// # Panics
+    /// Panics if the address family of the `struct sockaddr_storage` is invalid.
+    /// This should never happen.
+    /// If it does, it is likely because of an invalid pointer.
+    pub(crate) fn try_from_raw(sockaddr: SocketAddrStorage) -> Result<Self> {
+        match sockaddr.family()? {
+            AddressFamily::Inet => Ok(SocketAddr::V4(sockaddr.into())),
+            AddressFamily::Inet6 => Ok(SocketAddr::V6(sockaddr.into())),
+            _ => Err(code::EINVAL),
+        }
+    }
+}
+
+impl From<SocketAddrV4> for SocketAddr {
+    fn from(value: SocketAddrV4) -> Self {
+        SocketAddr::V4(value)
+    }
+}
+
+impl From<SocketAddrV6> for SocketAddr {
+    fn from(value: SocketAddrV6) -> Self {
+        SocketAddr::V6(value)
+    }
+}
+
+impl TryFrom<SocketAddr> for SocketAddrV4 {
+    type Error = Error;
+
+    fn try_from(value: SocketAddr) -> core::result::Result<Self, Self::Error> {
+        match value {
+            SocketAddr::V4(addr) => Ok(addr),
+            _ => Err(Error::from_errno(bindings::EAFNOSUPPORT as _)),
+        }
+    }
+}
+
+impl TryFrom<SocketAddr> for SocketAddrV6 {
+    type Error = Error;
+
+    fn try_from(value: SocketAddr) -> core::result::Result<Self, Self::Error> {
+        match value {
+            SocketAddr::V6(addr) => Ok(addr),
+            _ => Err(Error::from_errno(bindings::EAFNOSUPPORT as _)),
+        }
+    }
+}
+
+/// Generic trait for socket addresses.
+///
+/// The purpose of this trait is:
+/// - To force all socket addresses to have a size and an address family.
+/// - Force all socket addresses to implement specific built-in traits.
+pub trait GenericSocketAddr:
+    Sized + Copy + Clone + PartialEq + Eq + PartialOrd + Ord + Hash + Display
+{
+    /// Returns the size in bytes of the concrete address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::bindings;
+    /// use kernel::net::addr::{GenericSocketAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
+    /// assert_eq!(SocketAddrV4::size(), core::mem::size_of::<bindings::sockaddr_in>());
+    /// ```
+    fn size() -> usize
+    where
+        Self: Sized,
+    {
+        core::mem::size_of::<Self>()
+    }
+
+    /// Returns the address family of the concrete address.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use kernel::net::addr::{GenericSocketAddr, SocketAddrV4};
+    /// use kernel::net::AddressFamily;
+    /// assert_eq!(SocketAddrV4::family(), AddressFamily::Inet);
+    /// ```
+    fn family() -> AddressFamily;
+}
+
+/// IPv4 socket address.
+///
+/// Wraps a C `struct sockaddr_in`.
+///
+/// # Examples
+/// ```rust
+/// use kernel::bindings;
+/// use kernel::net::addr::{GenericSocketAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
+/// let addr = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 80);
+/// assert_eq!(addr.ip(), &Ipv4Addr::new(192, 168, 0, 1));
+/// assert_eq!(SocketAddrV4::size(), core::mem::size_of::<bindings::sockaddr_in>());
+/// ```
+#[repr(transparent)]
+#[derive(Copy, Clone)]
+pub struct SocketAddrV4(pub(crate) bindings::sockaddr_in);
+
+impl SocketAddrV4 {
+    /// The maximum length of a IPv4 socket address string representation.
+    ///
+    /// This is the length of the string representation of the address.
+    /// It does not include the null terminator.
+    pub const MAX_STRING_LEN: usize = 21;
+
+    /// Creates a new IPv4 socket address from an IP address and a port.
+    ///
+    /// The port does not need to be in network byte order.
+    pub const fn new(addr: Ipv4Addr, port: u16) -> Self {
+        Self(bindings::sockaddr_in {
+            sin_family: AddressFamily::Inet as _,
+            sin_port: port.to_be(),
+            sin_addr: addr.0,
+            __pad: [0; 8],
+        })
+    }
+
+    /// Returns a reference to the IP address contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddrV4};
+    ///
+    /// let ip = Ipv4Addr::new(192, 168, 0, 1);
+    /// let addr = SocketAddrV4::new(ip, 80);
+    /// assert_eq!(addr.ip(), &ip);
+    /// ```
+    pub const fn ip(&self) -> &Ipv4Addr {
+        // SAFETY: The [Ipv4Addr] is a transparent representation of the C `struct in_addr`,
+        // which is the type of `sin_addr`. Therefore, the conversion is safe.
+        unsafe { &*(&self.0.sin_addr as *const _ as *const Ipv4Addr) }
+    }
+
+    /// Change the IP address contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddrV4};
+    ///
+    /// let mut addr = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 80);
+    /// addr.set_ip(Ipv4Addr::new(192, 168, 0, 2));
+    /// assert_eq!(addr.ip(), &Ipv4Addr::new(192, 168, 0, 2));
+    /// ```
+    pub fn set_ip(&mut self, ip: Ipv4Addr) {
+        self.0.sin_addr = ip.0;
+    }
+
+    /// Returns the port contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddrV4};
+    ///
+    /// let addr = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 80);
+    /// assert_eq!(addr.port(), 81);
+    /// ```
+    pub const fn port(&self) -> u16 {
+        self.0.sin_port.to_be()
+    }
+
+    /// Change the port contained.
+    ///
+    /// The port does not need to be in network byte order.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddrV4};
+    ///
+    /// let mut addr = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 80);
+    /// addr.set_port(81);
+    /// assert_eq!(addr.port(), 81);
+    /// ```
+    pub fn set_port(&mut self, port: u16) {
+        self.0.sin_port = port.to_be();
+    }
+}
+
+impl GenericSocketAddr for SocketAddrV4 {
+    /// Returns the family of the address.
+    ///
+    /// # Invariants
+    /// The family is always [AddressFamily::Inet].
+    fn family() -> AddressFamily {
+        AddressFamily::Inet
+    }
+}
+
+impl PartialEq<SocketAddrV4> for SocketAddrV4 {
+    fn eq(&self, other: &SocketAddrV4) -> bool {
+        self.ip() == other.ip() && self.port() == other.port()
+    }
+}
+
+impl Eq for SocketAddrV4 {}
+
+impl Hash for SocketAddrV4 {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        (self.ip(), self.port()).hash(state)
+    }
+}
+
+impl PartialOrd for SocketAddrV4 {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for SocketAddrV4 {
+    fn cmp(&self, other: &Self) -> Ordering {
+        (self.ip(), self.port()).cmp(&(other.ip(), other.port()))
+    }
+}
+
+/// IPv6 socket address.
+///
+/// Wraps a C `struct sockaddr_in6`.
+///
+/// # Examples
+/// ```rust
+/// use kernel::bindings;
+/// use kernel::net::addr::{GenericSocketAddr, Ipv6Addr, SocketAddr, SocketAddrV6};
+///
+/// let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80, 0, 0);
+/// assert_eq!(addr.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+/// assert_eq!(SocketAddrV6::size(), core::mem::size_of::<bindings::sockaddr_in6>());
+#[repr(transparent)]
+#[derive(Copy, Clone)]
+pub struct SocketAddrV6(pub(crate) bindings::sockaddr_in6);
+
+impl SocketAddrV6 {
+    /// The maximum length of a IPv6 socket address string representation.
+    ///
+    /// This is the length of the string representation of the address.
+    /// It does not include the null terminator.
+    pub const MAX_STRING_LEN: usize = 74;
+
+    /// Creates a new IPv6 socket address from an IP address, a port, a flowinfo and a scope_id.
+    /// The port does not need to be in network byte order.
+    pub const fn new(addr: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> Self {
+        Self(bindings::sockaddr_in6 {
+            sin6_family: AddressFamily::Inet6 as _,
+            sin6_port: port.to_be(),
+            sin6_flowinfo: flowinfo,
+            sin6_addr: addr.0,
+            sin6_scope_id: scope_id,
+        })
+    }
+
+    /// Returns a reference to the IP address contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let ip = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+    /// let addr = SocketAddrV6::new(ip, 80, 0, 0);
+    /// assert_eq!(addr.ip(), &ip);
+    /// ```
+    pub const fn ip(&self) -> &Ipv6Addr {
+        // SAFETY: The [Ipv6Addr] is a transparent representation of the C `struct in6_addr`,
+        // which is the type of `sin6_addr`. Therefore, the conversion is safe.
+        unsafe { &*(&self.0.sin6_addr as *const _ as *const Ipv6Addr) }
+    }
+
+    /// Change the IP address contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let ip1 = Ipv6Addr::LOOPBACK;
+    /// let ip2 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 2);
+    /// let mut addr = SocketAddrV6::new(ip1, 80, 0, 0);
+    /// addr.set_ip(ip2);
+    /// assert_eq!(addr.ip(), &ip2);
+    /// ```
+    pub fn set_ip(&mut self, addr: Ipv6Addr) {
+        self.0.sin6_addr = addr.0;
+    }
+
+    /// Returns the port contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80, 0, 0);
+    /// assert_eq!(addr.port(), 80);
+    /// ```
+    pub const fn port(&self) -> u16 {
+        self.0.sin6_port.to_be()
+    }
+
+    /// Change the port contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let mut addr = SocketAddrV6::new(Ipv6Addr::LOOPBACK, 80, 0, 0);
+    /// addr.set_port(443);
+    /// assert_eq!(addr.port(), 443);
+    /// ```
+    pub fn set_port(&mut self, port: u16) {
+        self.0.sin6_port = port.to_be();
+    }
+
+    /// Returns the flowinfo contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80, 0, 0);
+    /// assert_eq!(addr.flowinfo(), 0);
+    /// ```
+    pub const fn flowinfo(&self) -> u32 {
+        self.0.sin6_flowinfo as _
+    }
+
+    /// Change the flowinfo contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let mut addr = SocketAddrV6::new(Ipv6Addr::LOOPBACK, 80, 0, 0);
+    /// addr.set_flowinfo(1);
+    /// assert_eq!(addr.flowinfo(), 1);
+    /// ```
+    pub fn set_flowinfo(&mut self, flowinfo: u32) {
+        self.0.sin6_flowinfo = flowinfo;
+    }
+
+    /// Returns the scope_id contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80, 0, 1);
+    /// assert_eq!(addr.scope_id(), 1);
+    /// ```
+    pub const fn scope_id(&self) -> u32 {
+        self.0.sin6_scope_id as _
+    }
+
+    /// Change the scope_id contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let mut addr = SocketAddrV6::new(Ipv6Addr::LOOPBACK, 80, 0, 0);
+    /// addr.set_scope_id(1);
+    /// assert_eq!(addr.scope_id(), 1);
+    /// ```
+    pub fn set_scope_id(&mut self, scope_id: u32) {
+        self.0.sin6_scope_id = scope_id;
+    }
+}
+
+impl GenericSocketAddr for SocketAddrV6 {
+    /// Returns the family of the address.
+    ///
+    /// # Invariants
+    /// The family is always [AddressFamily::Inet6].
+    fn family() -> AddressFamily {
+        AddressFamily::Inet6
+    }
+}
+
+impl PartialEq<SocketAddrV6> for SocketAddrV6 {
+    fn eq(&self, other: &SocketAddrV6) -> bool {
+        self.ip() == other.ip()
+            && self.port() == other.port()
+            && self.flowinfo() == other.flowinfo()
+            && self.scope_id() == other.scope_id()
+    }
+}
+
+impl Eq for SocketAddrV6 {}
+
+impl Hash for SocketAddrV6 {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        (self.ip(), self.port(), self.flowinfo(), self.scope_id()).hash(state)
+    }
+}
+
+impl PartialOrd for SocketAddrV6 {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for SocketAddrV6 {
+    fn cmp(&self, other: &Self) -> Ordering {
+        (self.ip(), self.port(), self.flowinfo(), self.scope_id()).cmp(&(
+            other.ip(),
+            other.port(),
+            other.flowinfo(),
+            other.scope_id(),
+        ))
+    }
+}
+
+/// Create a Socket address from a string.
+///
+/// This method is a wrapper for the `inet_pton_with_scope` C function, which transforms a string
+/// to the specified sockaddr* structure.
+fn address_from_string<T: GenericSocketAddr>(src: &str, port: &str, net: &Namespace) -> Result<T> {
+    let src = CString::try_from_fmt(fmt!("{}", src))?;
+    let port = CString::try_from_fmt(fmt!("{}", port))?;
+    let mut addr = MaybeUninit::<T>::zeroed();
+
+    // SAFETY: FFI call, all pointers are valid for the duration of the call.
+    //         The address family matches the address structure.
+    match unsafe {
+        bindings::inet_pton_with_scope(
+            net as *const _ as *mut bindings::net as _,
+            T::family() as _,
+            src.as_ptr() as _,
+            port.as_ptr() as _,
+            addr.as_mut_ptr() as _,
+        )
+    } {
+        // SAFETY: The address was initialized by the C function.
+        //         Whatever was not initialized, e.g. flow info or scope id for ipv6, are zeroed.
+        0 => Ok(unsafe { addr.assume_init() }),
+        errno => Err(Error::from_errno(errno as _)),
+    }
+}
+
+/// Write the string representation of the `T` address to the formatter.
+///
+/// This function is used to implement the `Display` trait for each address.
+///
+/// The `cfmt` parameter is the C string format used to format the address.
+/// For example, the format for an IPv4 address is `"%pI4"`.
+///
+/// The `BUF_LEN` parameter is the size of the buffer used to format the address, including the null terminator.
+///
+/// # Safety
+/// In order to have a correct output, the `cfmt` parameter must be a valid C string format for the `T` address.
+/// Also, the `BUF_LEN` parameter must be at least the length of the string representation of the address.
+unsafe fn write_addr<const BUF_LEN: usize, T: Sized>(
+    formatter: &mut Formatter<'_>,
+    cfmt: &CStr,
+    addr: &T,
+) -> core::fmt::Result {
+    let mut buff = [0u8; BUF_LEN];
+    // SAFETY: the buffer is big enough to contain the string representation of the address.
+    //         The format is valid for the address.
+    let s = match unsafe {
+        bindings::snprintf(
+            buff.as_mut_ptr() as _,
+            BUF_LEN as _,
+            cfmt.as_ptr() as _,
+            addr as *const T,
+        )
+    } {
+        n if n < 0 => Err(()),
+
+        // the buffer is probably bigger than the actual string: truncate at the first null byte
+        _ => buff
+            .iter()
+            .position(|&c| c == 0)
+            // SAFETY: the buffer contains a UTF-8 valid string and contains a single null terminator.
+            .map(|i| unsafe { core::str::from_utf8_unchecked(&buff[..i]) })
+            .ok_or(()),
+    };
+    match s {
+        Ok(s) => write!(formatter, "{}", s),
+        Err(_) => Err(core::fmt::Error),
+    }
+}
+
+impl Display for Ipv4Addr {
+    /// Display the address as a string.
+    /// The bytes are in network order.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    /// use kernel::pr_info;
+    ///
+    /// let addr = Ipv4Addr::new(192, 168, 0, 1);
+    /// pr_info!("{}", addr); // prints "192.168.0.1"
+    /// ```
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        // SAFETY: MAX_STRING_LEN is the length of 255.255.255.255, the biggest Ipv4Addr string.
+        //         +1 for the null terminator.
+        unsafe {
+            write_addr::<{ Ipv4Addr::MAX_STRING_LEN + 1 }, Ipv4Addr>(f, c_str!("%pI4"), self)
+                .map_err(|_| core::fmt::Error)
+        }
+    }
+}
+
+impl Debug for Ipv4Addr {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        write!(f, "Ipv4Addr({})", self)
+    }
+}
+
+impl FromStr for Ipv4Addr {
+    type Err = ();
+
+    /// Create a new IPv4 address from a string.
+    /// The string must be in the format `a.b.c.d`, where `a`, `b`, `c` and `d` are 8-bit integers.
+    ///
+    /// # Examples
+    /// Valid addresses:
+    /// ```rust
+    /// use core::str::FromStr;
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::from_str("192.168.0.1");
+    /// assert_eq!(addr, Ok(Ipv4Addr::new(192, 168, 0, 1)));
+    /// ```
+    ///
+    /// Invalid addresses:
+    /// ```rust
+    /// use core::str::FromStr;
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let mut addr = Ipv4Addr::from_str("invalid");
+    /// assert_eq!(addr, Err(()));
+    ///
+    /// addr = Ipv4Addr::from_str("280.168.0.1");
+    /// assert_eq!(addr, Err(()));
+    ///
+    /// addr = Ipv4Addr::from_str("0.0.0.0.0");
+    /// assert_eq!(addr, Err(()));
+    /// ```
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let mut buffer = [0u8; 4];
+        // SAFETY: FFI call,
+        //         there is no need to construct a NULL-terminated string, as the length is passed.
+        match unsafe {
+            bindings::in4_pton(
+                s.as_ptr() as *const _,
+                s.len() as _,
+                buffer.as_mut_ptr() as _,
+                -1,
+                ptr::null_mut(),
+            )
+        } {
+            1 => Ok(Ipv4Addr::from(buffer)),
+            _ => Err(()),
+        }
+    }
+}
+
+impl Display for Ipv6Addr {
+    /// Display the address as a string.
+    /// The bytes are in network order.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv6Addr;
+    /// use kernel::pr_info;
+    ///
+    /// let addr = Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334);
+    /// pr_info!("{}", addr); // prints "2001:db8:85a3::8a2e:370:7334"
+    /// ```
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        // SAFETY: MAX_STRING_LEN is the length of ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff, the biggest Ipv6Addr string.
+        unsafe {
+            write_addr::<{ Ipv6Addr::MAX_STRING_LEN + 1 }, Ipv6Addr>(f, c_str!("%pI6c"), self)
+        }
+    }
+}
+
+impl Debug for Ipv6Addr {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        write!(f, "Ipv6Addr({})", self)
+    }
+}
+
+impl FromStr for Ipv6Addr {
+    type Err = ();
+
+    /// Create a new IPv6 address from a string.
+    ///
+    /// The address must follow the format described in [RFC 4291](https://tools.ietf.org/html/rfc4291#section-2.2).
+    ///
+    /// # Examples
+    /// Valid addresses:
+    /// ```rust
+    /// use core::str::FromStr;
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::from_str("2001:db8:85a3:0:0:8a2e:370:7334").unwrap();
+    /// assert_eq!(addr, Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334));
+    /// ```
+    ///
+    /// Invalid addresses:
+    /// ```rust
+    /// use core::str::FromStr;
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let mut addr = Ipv6Addr::from_str("invalid");
+    /// assert_eq!(addr, Err(()));
+    ///
+    /// addr = Ipv6Addr::from_str("2001:db8:85a3:0:0:8a2e:370:7334:1234");
+    /// assert_eq!(addr, Err(()));
+    /// ```
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let mut buffer = [0u8; 16];
+        // SAFETY: FFI call,
+        //         there is no need to construct a NULL-terminated string, as the length is passed.
+        match unsafe {
+            bindings::in6_pton(
+                s.as_ptr() as _,
+                s.len() as _,
+                buffer.as_mut_ptr() as _,
+                -1,
+                ptr::null_mut(),
+            )
+        } {
+            1 => Ok(Ipv6Addr::from(buffer)),
+            _ => Err(()),
+        }
+    }
+}
+
+impl Display for SocketAddr {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        match self {
+            SocketAddr::V4(addr) => Display::fmt(addr, f),
+            SocketAddr::V6(addr) => Display::fmt(addr, f),
+        }
+    }
+}
+
+impl Debug for SocketAddr {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        write!(f, "SocketAddr({})", self)
+    }
+}
+
+impl FromStr for SocketAddr {
+    type Err = Error;
+
+    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
+        let funcs = [
+            |s| SocketAddrV4::from_str(s).map(SocketAddr::V4),
+            |s| SocketAddrV6::from_str(s).map(SocketAddr::V6),
+        ];
+
+        funcs.iter().find_map(|f| f(s).ok()).ok_or(code::EINVAL)
+    }
+}
+
+impl Display for SocketAddrV4 {
+    /// Display the address as a string.
+    ///
+    /// The output is of the form `address:port`, where `address` is the IP address in dotted
+    /// decimal notation, and `port` is the port number.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::SocketAddrV4;
+    /// use kernel::pr_info;
+    ///
+    /// let addr = SocketAddrV4::from_str("1.2.3.4:5678").unwrap();
+    /// pr_info!("{}", addr); // prints "1.2.3.4:5678"
+    /// ```
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        // SAFETY: MAX_STRING_LEN is the length of 255.255.255.255:12345, the biggest SocketAddrV4 string.
+        unsafe {
+            write_addr::<{ SocketAddrV4::MAX_STRING_LEN + 1 }, SocketAddrV4>(
+                f,
+                c_str!("%pISpc"),
+                self,
+            )
+        }
+    }
+}
+
+impl Debug for SocketAddrV4 {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        write!(f, "SocketAddrV4({})", self)
+    }
+}
+
+impl FromStr for SocketAddrV4 {
+    type Err = Error;
+
+    /// Parses a string as an IPv4 socket address.
+    ///
+    /// The string must be in the form `a.b.c.d:p`, where `a`, `b`, `c`, `d` are the four
+    /// components of the IPv4 address, and `p` is the port.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddrV4};
+    ///
+    /// // valid
+    /// let addr = SocketAddrV4::from_str("192.168.1.0:80").unwrap();
+    /// assert_eq!(addr.ip(), &Ipv4Addr::new(192, 168, 1, 0));
+    /// assert_eq!(addr.port(), 80);
+    ///
+    /// // invalid
+    /// assert!(SocketAddrV4::from_str("192.168:800:80").is_err());
+    /// ```
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let (addr, port) = s.split_once(':').ok_or(code::EINVAL)?;
+        address_from_string(addr, port, init_net())
+    }
+}
+
+impl Display for SocketAddrV6 {
+    /// Display the address as a string.
+    ///
+    /// The output string is of the form `[addr]:port`, where `addr` is an IPv6 address and `port`
+    /// is a port number.
+    ///
+    /// Flow info and scope ID are not supported and are excluded from the output.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let addr = SocketAddrV6::from_str("[::1]:80").unwrap();
+    /// pr_info!("{}", addr);  // prints "[::1]:80"
+    /// ```
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        // SAFETY: MAX_STRING_LEN is big enough to hold the biggest SocketAddrV6 string.
+        unsafe {
+            write_addr::<{ SocketAddrV6::MAX_STRING_LEN + 1 }, SocketAddrV6>(
+                f,
+                c_str!("%pISpc"),
+                self,
+            )
+        }
+    }
+}
+
+impl Debug for SocketAddrV6 {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        write!(f, "SocketAddrV6({})", self)
+    }
+}
+
+impl FromStr for SocketAddrV6 {
+    type Err = Error;
+
+    /// Parses a string as an IPv6 socket address.
+    ///
+    /// The given string must be of the form `[addr]:port`, where `addr` is an IPv6 address and
+    /// `port` is a port number.
+    ///
+    /// Flow info and scope ID are not supported.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// // valid
+    /// let addr = SocketAddrV6::from_str("[2001:db8:85a3::8a2e:370:7334]:80").unwrap();
+    /// assert_eq!(addr.ip(), &Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334));
+    /// assert_eq!(addr.port(), 80);
+    /// ```
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let (addr, port) = s.rsplit_once(':').ok_or(code::EINVAL)?;
+        let address = addr.trim_start_matches('[').trim_end_matches(']');
+        address_from_string(address, port, init_net())
+    }
+}
-- 
2.41.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ