about summary refs log tree commit diff
path: root/library/std/src/sys
diff options
context:
space:
mode:
author许杰友 Jieyou Xu (Joe) <39484203+jieyouxu@users.noreply.github.com>2025-02-05 19:09:35 +0800
committerGitHub <noreply@github.com>2025-02-05 19:09:35 +0800
commitff339fbbf4c535afdff3ceaa968f0fe36be23b59 (patch)
tree741ba861f64fd404bc996559a9af467a8ff3dd51 /library/std/src/sys
parentcc58e8b7ec3c09a04b4d2420ee9a328bfad73e15 (diff)
parent8a3cb1351183e963da96ae6bbb8dcce478be9f7b (diff)
downloadrust-ff339fbbf4c535afdff3ceaa968f0fe36be23b59.tar.gz
rust-ff339fbbf4c535afdff3ceaa968f0fe36be23b59.zip
Rollup merge of #136449 - joboet:move_pal_net, r=ChrisDenton
std: move network code into `sys`

As per #117276, this PR moves `sys_common::net` and the `sys::pal::net` into the newly created `sys::net` module. In order to support #135141, I've moved all the current network code into a separate `connection` module, future functions like `hostname` can live in separate modules.

I'll probably do a follow-up PR and clean up some of the actual code, this is mostly just a reorganization.
Diffstat (limited to 'library/std/src/sys')
-rw-r--r--library/std/src/sys/mod.rs1
-rw-r--r--library/std/src/sys/net/connection/sgx.rs (renamed from library/std/src/sys/pal/sgx/net.rs)2
-rw-r--r--library/std/src/sys/net/connection/socket.rs780
-rw-r--r--library/std/src/sys/net/connection/socket/hermit.rs (renamed from library/std/src/sys/pal/hermit/net.rs)13
-rw-r--r--library/std/src/sys/net/connection/socket/solid.rs (renamed from library/std/src/sys/pal/solid/net.rs)24
-rw-r--r--library/std/src/sys/net/connection/socket/tests.rs19
-rw-r--r--library/std/src/sys/net/connection/socket/unix.rs (renamed from library/std/src/sys/pal/unix/net.rs)10
-rw-r--r--library/std/src/sys/net/connection/socket/wasip2.rs (renamed from library/std/src/sys/pal/wasip2/net.rs)2
-rw-r--r--library/std/src/sys/net/connection/socket/windows.rs (renamed from library/std/src/sys/pal/windows/net.rs)21
-rw-r--r--library/std/src/sys/net/connection/unsupported.rs (renamed from library/std/src/sys/pal/unsupported/net.rs)0
-rw-r--r--library/std/src/sys/net/connection/wasip1.rs (renamed from library/std/src/sys/pal/wasi/net.rs)5
-rw-r--r--library/std/src/sys/net/connection/xous/dns.rs (renamed from library/std/src/sys/pal/xous/net/dns.rs)0
-rw-r--r--library/std/src/sys/net/connection/xous/mod.rs (renamed from library/std/src/sys/pal/xous/net/mod.rs)0
-rw-r--r--library/std/src/sys/net/connection/xous/tcplistener.rs (renamed from library/std/src/sys/pal/xous/net/tcplistener.rs)0
-rw-r--r--library/std/src/sys/net/connection/xous/tcpstream.rs (renamed from library/std/src/sys/pal/xous/net/tcpstream.rs)0
-rw-r--r--library/std/src/sys/net/connection/xous/udp.rs (renamed from library/std/src/sys/pal/xous/net/udp.rs)0
-rw-r--r--library/std/src/sys/net/mod.rs36
-rw-r--r--library/std/src/sys/pal/hermit/mod.rs1
-rw-r--r--library/std/src/sys/pal/sgx/mod.rs1
-rw-r--r--library/std/src/sys/pal/solid/error.rs3
-rw-r--r--library/std/src/sys/pal/solid/mod.rs3
-rw-r--r--library/std/src/sys/pal/teeos/mod.rs1
-rw-r--r--library/std/src/sys/pal/teeos/net.rs369
-rw-r--r--library/std/src/sys/pal/uefi/mod.rs2
-rw-r--r--library/std/src/sys/pal/unix/l4re.rs564
-rw-r--r--library/std/src/sys/pal/unix/mod.rs6
-rw-r--r--library/std/src/sys/pal/unsupported/mod.rs1
-rw-r--r--library/std/src/sys/pal/wasi/mod.rs4
-rw-r--r--library/std/src/sys/pal/wasip2/mod.rs1
-rw-r--r--library/std/src/sys/pal/wasm/mod.rs2
-rw-r--r--library/std/src/sys/pal/windows/mod.rs3
-rw-r--r--library/std/src/sys/pal/xous/mod.rs1
-rw-r--r--library/std/src/sys/pal/zkvm/mod.rs2
33 files changed, 873 insertions, 1004 deletions
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index f17dd47dece..39a0bc6e337 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -12,6 +12,7 @@ pub mod anonymous_pipe;
 pub mod backtrace;
 pub mod cmath;
 pub mod exit_guard;
+pub mod net;
 pub mod os_str;
 pub mod path;
 pub mod random;
diff --git a/library/std/src/sys/pal/sgx/net.rs b/library/std/src/sys/net/connection/sgx.rs
index c966886d163..b390a5eac5f 100644
--- a/library/std/src/sys/pal/sgx/net.rs
+++ b/library/std/src/sys/net/connection/sgx.rs
@@ -1,7 +1,7 @@
-use super::abi::usercalls;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
 use crate::sync::Arc;
+use crate::sys::abi::usercalls;
 use crate::sys::fd::FileDesc;
 use crate::sys::{AsInner, FromInner, IntoInner, TryIntoInner, sgx_ineffective, unsupported};
 use crate::time::Duration;
diff --git a/library/std/src/sys/net/connection/socket.rs b/library/std/src/sys/net/connection/socket.rs
new file mode 100644
index 00000000000..6fe3430b53f
--- /dev/null
+++ b/library/std/src/sys/net/connection/socket.rs
@@ -0,0 +1,780 @@
+#[cfg(test)]
+mod tests;
+
+use crate::ffi::{c_int, c_void};
+use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut};
+use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+use crate::sys::common::small_c_string::run_with_cstr;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::Duration;
+use crate::{cmp, fmt, mem, ptr};
+
+cfg_if::cfg_if! {
+    if #[cfg(target_os = "hermit")] {
+        mod hermit;
+        pub use hermit::*;
+    } else if #[cfg(target_os = "solid_asp3")] {
+        mod solid;
+        pub use solid::*;
+    } else if #[cfg(target_family = "unix")] {
+        mod unix;
+        pub use unix::*;
+    } else if #[cfg(all(target_os = "wasi", target_env = "p2"))] {
+        mod wasip2;
+        pub use wasip2::*;
+    } else if #[cfg(target_os = "windows")] {
+        mod windows;
+        pub use windows::*;
+    }
+}
+
+use netc as c;
+
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "dragonfly",
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "illumos",
+        target_os = "solaris",
+        target_os = "haiku",
+        target_os = "l4re",
+        target_os = "nto",
+        target_os = "nuttx",
+        target_vendor = "apple",
+    ))] {
+        use c::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
+        use c::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
+    } else {
+        use c::IPV6_ADD_MEMBERSHIP;
+        use c::IPV6_DROP_MEMBERSHIP;
+    }
+}
+
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "linux", target_os = "android",
+        target_os = "hurd",
+        target_os = "dragonfly", target_os = "freebsd",
+        target_os = "openbsd", target_os = "netbsd",
+        target_os = "solaris", target_os = "illumos",
+        target_os = "haiku", target_os = "nto"))] {
+        use libc::MSG_NOSIGNAL;
+    } else {
+        const MSG_NOSIGNAL: c_int = 0x0;
+    }
+}
+
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "dragonfly", target_os = "freebsd",
+        target_os = "openbsd", target_os = "netbsd",
+        target_os = "solaris", target_os = "illumos",
+        target_os = "nto"))] {
+        use crate::ffi::c_uchar;
+        type IpV4MultiCastType = c_uchar;
+    } else {
+        type IpV4MultiCastType = c_int;
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// sockaddr and misc bindings
+////////////////////////////////////////////////////////////////////////////////
+
+pub fn setsockopt<T>(
+    sock: &Socket,
+    level: c_int,
+    option_name: c_int,
+    option_value: T,
+) -> io::Result<()> {
+    unsafe {
+        cvt(c::setsockopt(
+            sock.as_raw(),
+            level,
+            option_name,
+            (&raw const option_value) as *const _,
+            mem::size_of::<T>() as c::socklen_t,
+        ))?;
+        Ok(())
+    }
+}
+
+pub fn getsockopt<T: Copy>(sock: &Socket, level: c_int, option_name: c_int) -> io::Result<T> {
+    unsafe {
+        let mut option_value: T = mem::zeroed();
+        let mut option_len = mem::size_of::<T>() as c::socklen_t;
+        cvt(c::getsockopt(
+            sock.as_raw(),
+            level,
+            option_name,
+            (&raw mut option_value) as *mut _,
+            &mut option_len,
+        ))?;
+        Ok(option_value)
+    }
+}
+
+fn sockname<F>(f: F) -> io::Result<SocketAddr>
+where
+    F: FnOnce(*mut c::sockaddr, *mut c::socklen_t) -> c_int,
+{
+    unsafe {
+        let mut storage: c::sockaddr_storage = mem::zeroed();
+        let mut len = mem::size_of_val(&storage) as c::socklen_t;
+        cvt(f((&raw mut storage) as *mut _, &mut len))?;
+        sockaddr_to_addr(&storage, len as usize)
+    }
+}
+
+pub fn sockaddr_to_addr(storage: &c::sockaddr_storage, len: usize) -> io::Result<SocketAddr> {
+    match storage.ss_family as c_int {
+        c::AF_INET => {
+            assert!(len >= mem::size_of::<c::sockaddr_in>());
+            Ok(SocketAddr::V4(FromInner::from_inner(unsafe {
+                *(storage as *const _ as *const c::sockaddr_in)
+            })))
+        }
+        c::AF_INET6 => {
+            assert!(len >= mem::size_of::<c::sockaddr_in6>());
+            Ok(SocketAddr::V6(FromInner::from_inner(unsafe {
+                *(storage as *const _ as *const c::sockaddr_in6)
+            })))
+        }
+        _ => Err(io::const_error!(ErrorKind::InvalidInput, "invalid argument")),
+    }
+}
+
+#[cfg(target_os = "android")]
+fn to_ipv6mr_interface(value: u32) -> c_int {
+    value as c_int
+}
+
+#[cfg(not(target_os = "android"))]
+fn to_ipv6mr_interface(value: u32) -> crate::ffi::c_uint {
+    value as crate::ffi::c_uint
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// get_host_addresses
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct LookupHost {
+    original: *mut c::addrinfo,
+    cur: *mut c::addrinfo,
+    port: u16,
+}
+
+impl LookupHost {
+    pub fn port(&self) -> u16 {
+        self.port
+    }
+}
+
+impl Iterator for LookupHost {
+    type Item = SocketAddr;
+    fn next(&mut self) -> Option<SocketAddr> {
+        loop {
+            unsafe {
+                let cur = self.cur.as_ref()?;
+                self.cur = cur.ai_next;
+                match sockaddr_to_addr(mem::transmute(cur.ai_addr), cur.ai_addrlen as usize) {
+                    Ok(addr) => return Some(addr),
+                    Err(_) => continue,
+                }
+            }
+        }
+    }
+}
+
+unsafe impl Sync for LookupHost {}
+unsafe impl Send for LookupHost {}
+
+impl Drop for LookupHost {
+    fn drop(&mut self) {
+        unsafe { c::freeaddrinfo(self.original) }
+    }
+}
+
+impl TryFrom<&str> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(s: &str) -> io::Result<LookupHost> {
+        macro_rules! try_opt {
+            ($e:expr, $msg:expr) => {
+                match $e {
+                    Some(r) => r,
+                    None => return Err(io::const_error!(io::ErrorKind::InvalidInput, $msg)),
+                }
+            };
+        }
+
+        // split the string by ':' and convert the second part to u16
+        let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address");
+        let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
+        (host, port).try_into()
+    }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
+        init();
+
+        run_with_cstr(host.as_bytes(), &|c_host| {
+            let mut hints: c::addrinfo = unsafe { mem::zeroed() };
+            hints.ai_socktype = c::SOCK_STREAM;
+            let mut res = ptr::null_mut();
+            unsafe {
+                cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res))
+                    .map(|_| LookupHost { original: res, cur: res, port })
+            }
+        })
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TCP streams
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct TcpStream {
+    inner: Socket,
+}
+
+impl TcpStream {
+    pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+        let addr = addr?;
+
+        init();
+
+        let sock = Socket::new(addr, c::SOCK_STREAM)?;
+        sock.connect(addr)?;
+        Ok(TcpStream { inner: sock })
+    }
+
+    pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
+        init();
+
+        let sock = Socket::new(addr, c::SOCK_STREAM)?;
+        sock.connect_timeout(addr, timeout)?;
+        Ok(TcpStream { inner: sock })
+    }
+
+    #[inline]
+    pub fn socket(&self) -> &Socket {
+        &self.inner
+    }
+
+    pub fn into_socket(self) -> Socket {
+        self.inner
+    }
+
+    pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+        self.inner.set_timeout(dur, c::SO_RCVTIMEO)
+    }
+
+    pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+        self.inner.set_timeout(dur, c::SO_SNDTIMEO)
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        self.inner.timeout(c::SO_RCVTIMEO)
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        self.inner.timeout(c::SO_SNDTIMEO)
+    }
+
+    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.inner.peek(buf)
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.inner.read(buf)
+    }
+
+    pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
+        self.inner.read_buf(buf)
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        self.inner.read_vectored(bufs)
+    }
+
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
+        let ret = cvt(unsafe {
+            c::send(self.inner.as_raw(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL)
+        })?;
+        Ok(ret as usize)
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        self.inner.write_vectored(bufs)
+    }
+
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        self.inner.is_write_vectored()
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) })
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) })
+    }
+
+    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+        self.inner.shutdown(how)
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpStream> {
+        self.inner.duplicate().map(|s| TcpStream { inner: s })
+    }
+
+    pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
+        self.inner.set_linger(linger)
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        self.inner.linger()
+    }
+
+    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+        self.inner.set_nodelay(nodelay)
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        self.inner.nodelay()
+    }
+
+    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+        setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
+        Ok(raw as u32)
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.inner.take_error()
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        self.inner.set_nonblocking(nonblocking)
+    }
+}
+
+impl AsInner<Socket> for TcpStream {
+    #[inline]
+    fn as_inner(&self) -> &Socket {
+        &self.inner
+    }
+}
+
+impl FromInner<Socket> for TcpStream {
+    fn from_inner(socket: Socket) -> TcpStream {
+        TcpStream { inner: socket }
+    }
+}
+
+impl fmt::Debug for TcpStream {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut res = f.debug_struct("TcpStream");
+
+        if let Ok(addr) = self.socket_addr() {
+            res.field("addr", &addr);
+        }
+
+        if let Ok(peer) = self.peer_addr() {
+            res.field("peer", &peer);
+        }
+
+        let name = if cfg!(windows) { "socket" } else { "fd" };
+        res.field(name, &self.inner.as_raw()).finish()
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TCP listeners
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct TcpListener {
+    inner: Socket,
+}
+
+impl TcpListener {
+    pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+        let addr = addr?;
+
+        init();
+
+        let sock = Socket::new(addr, c::SOCK_STREAM)?;
+
+        // On platforms with Berkeley-derived sockets, this allows to quickly
+        // rebind a socket, without needing to wait for the OS to clean up the
+        // previous one.
+        //
+        // On Windows, this allows rebinding sockets which are actively in use,
+        // which allows “socket hijacking”, so we explicitly don't set it here.
+        // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse
+        #[cfg(not(windows))]
+        setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?;
+
+        // Bind our new socket
+        let (addr, len) = addr.into_inner();
+        cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
+
+        cfg_if::cfg_if! {
+            if #[cfg(target_os = "horizon")] {
+                // The 3DS doesn't support a big connection backlog. Sometimes
+                // it allows up to about 37, but other times it doesn't even
+                // accept 32. There may be a global limitation causing this.
+                let backlog = 20;
+            } else if #[cfg(target_os = "haiku")] {
+                // Haiku does not support a queue length > 32
+                // https://github.com/haiku/haiku/blob/979a0bc487864675517fb2fab28f87dc8bf43041/headers/posix/sys/socket.h#L81
+                let backlog = 32;
+            } else {
+                // The default for all other platforms
+                let backlog = 128;
+            }
+        }
+
+        // Start listening
+        cvt(unsafe { c::listen(sock.as_raw(), backlog) })?;
+        Ok(TcpListener { inner: sock })
+    }
+
+    #[inline]
+    pub fn socket(&self) -> &Socket {
+        &self.inner
+    }
+
+    pub fn into_socket(self) -> Socket {
+        self.inner
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) })
+    }
+
+    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+        let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() };
+        let mut len = mem::size_of_val(&storage) as c::socklen_t;
+        let sock = self.inner.accept((&raw mut storage) as *mut _, &mut len)?;
+        let addr = sockaddr_to_addr(&storage, len as usize)?;
+        Ok((TcpStream { inner: sock }, addr))
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpListener> {
+        self.inner.duplicate().map(|s| TcpListener { inner: s })
+    }
+
+    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+        setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
+        Ok(raw as u32)
+    }
+
+    pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+        setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int)
+    }
+
+    pub fn only_v6(&self) -> io::Result<bool> {
+        let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY)?;
+        Ok(raw != 0)
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.inner.take_error()
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        self.inner.set_nonblocking(nonblocking)
+    }
+}
+
+impl FromInner<Socket> for TcpListener {
+    fn from_inner(socket: Socket) -> TcpListener {
+        TcpListener { inner: socket }
+    }
+}
+
+impl fmt::Debug for TcpListener {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut res = f.debug_struct("TcpListener");
+
+        if let Ok(addr) = self.socket_addr() {
+            res.field("addr", &addr);
+        }
+
+        let name = if cfg!(windows) { "socket" } else { "fd" };
+        res.field(name, &self.inner.as_raw()).finish()
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// UDP
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UdpSocket {
+    inner: Socket,
+}
+
+impl UdpSocket {
+    pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+        let addr = addr?;
+
+        init();
+
+        let sock = Socket::new(addr, c::SOCK_DGRAM)?;
+        let (addr, len) = addr.into_inner();
+        cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
+        Ok(UdpSocket { inner: sock })
+    }
+
+    #[inline]
+    pub fn socket(&self) -> &Socket {
+        &self.inner
+    }
+
+    pub fn into_socket(self) -> Socket {
+        self.inner
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) })
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) })
+    }
+
+    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.inner.recv_from(buf)
+    }
+
+    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.inner.peek_from(buf)
+    }
+
+    pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
+        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
+        let (dst, dstlen) = dst.into_inner();
+        let ret = cvt(unsafe {
+            c::sendto(
+                self.inner.as_raw(),
+                buf.as_ptr() as *const c_void,
+                len,
+                MSG_NOSIGNAL,
+                dst.as_ptr(),
+                dstlen,
+            )
+        })?;
+        Ok(ret as usize)
+    }
+
+    pub fn duplicate(&self) -> io::Result<UdpSocket> {
+        self.inner.duplicate().map(|s| UdpSocket { inner: s })
+    }
+
+    pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+        self.inner.set_timeout(dur, c::SO_RCVTIMEO)
+    }
+
+    pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+        self.inner.set_timeout(dur, c::SO_SNDTIMEO)
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        self.inner.timeout(c::SO_RCVTIMEO)
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        self.inner.timeout(c::SO_SNDTIMEO)
+    }
+
+    pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
+        setsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST, broadcast as c_int)
+    }
+
+    pub fn broadcast(&self) -> io::Result<bool> {
+        let raw: c_int = getsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST)?;
+        Ok(raw != 0)
+    }
+
+    pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
+        setsockopt(
+            &self.inner,
+            c::IPPROTO_IP,
+            c::IP_MULTICAST_LOOP,
+            multicast_loop_v4 as IpV4MultiCastType,
+        )
+    }
+
+    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+        let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?;
+        Ok(raw != 0)
+    }
+
+    pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
+        setsockopt(
+            &self.inner,
+            c::IPPROTO_IP,
+            c::IP_MULTICAST_TTL,
+            multicast_ttl_v4 as IpV4MultiCastType,
+        )
+    }
+
+    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+        let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?;
+        Ok(raw as u32)
+    }
+
+    pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
+        setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP, multicast_loop_v6 as c_int)
+    }
+
+    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+        let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP)?;
+        Ok(raw != 0)
+    }
+
+    pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
+        let mreq = c::ip_mreq {
+            imr_multiaddr: multiaddr.into_inner(),
+            imr_interface: interface.into_inner(),
+        };
+        setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq)
+    }
+
+    pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
+        let mreq = c::ipv6_mreq {
+            ipv6mr_multiaddr: multiaddr.into_inner(),
+            ipv6mr_interface: to_ipv6mr_interface(interface),
+        };
+        setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq)
+    }
+
+    pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
+        let mreq = c::ip_mreq {
+            imr_multiaddr: multiaddr.into_inner(),
+            imr_interface: interface.into_inner(),
+        };
+        setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq)
+    }
+
+    pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
+        let mreq = c::ipv6_mreq {
+            ipv6mr_multiaddr: multiaddr.into_inner(),
+            ipv6mr_interface: to_ipv6mr_interface(interface),
+        };
+        setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq)
+    }
+
+    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+        setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
+        Ok(raw as u32)
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.inner.take_error()
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        self.inner.set_nonblocking(nonblocking)
+    }
+
+    pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.inner.read(buf)
+    }
+
+    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.inner.peek(buf)
+    }
+
+    pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
+        let ret = cvt(unsafe {
+            c::send(self.inner.as_raw(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL)
+        })?;
+        Ok(ret as usize)
+    }
+
+    pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> {
+        let (addr, len) = addr?.into_inner();
+        cvt_r(|| unsafe { c::connect(self.inner.as_raw(), addr.as_ptr(), len) }).map(drop)
+    }
+}
+
+impl FromInner<Socket> for UdpSocket {
+    fn from_inner(socket: Socket) -> UdpSocket {
+        UdpSocket { inner: socket }
+    }
+}
+
+impl fmt::Debug for UdpSocket {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut res = f.debug_struct("UdpSocket");
+
+        if let Ok(addr) = self.socket_addr() {
+            res.field("addr", &addr);
+        }
+
+        let name = if cfg!(windows) { "socket" } else { "fd" };
+        res.field(name, &self.inner.as_raw()).finish()
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Converting SocketAddr to libc representation
+////////////////////////////////////////////////////////////////////////////////
+
+/// A type with the same memory layout as `c::sockaddr`. Used in converting Rust level
+/// SocketAddr* types into their system representation. The benefit of this specific
+/// type over using `c::sockaddr_storage` is that this type is exactly as large as it
+/// needs to be and not a lot larger. And it can be initialized more cleanly from Rust.
+#[repr(C)]
+pub(crate) union SocketAddrCRepr {
+    v4: c::sockaddr_in,
+    v6: c::sockaddr_in6,
+}
+
+impl SocketAddrCRepr {
+    pub fn as_ptr(&self) -> *const c::sockaddr {
+        self as *const _ as *const c::sockaddr
+    }
+}
+
+impl<'a> IntoInner<(SocketAddrCRepr, c::socklen_t)> for &'a SocketAddr {
+    fn into_inner(self) -> (SocketAddrCRepr, c::socklen_t) {
+        match *self {
+            SocketAddr::V4(ref a) => {
+                let sockaddr = SocketAddrCRepr { v4: a.into_inner() };
+                (sockaddr, mem::size_of::<c::sockaddr_in>() as c::socklen_t)
+            }
+            SocketAddr::V6(ref a) => {
+                let sockaddr = SocketAddrCRepr { v6: a.into_inner() };
+                (sockaddr, mem::size_of::<c::sockaddr_in6>() as c::socklen_t)
+            }
+        }
+    }
+}
diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/net/connection/socket/hermit.rs
index 4e12374203e..42179dcc915 100644
--- a/library/std/src/sys/pal/hermit/net.rs
+++ b/library/std/src/sys/net/connection/socket/hermit.rs
@@ -2,21 +2,20 @@
 
 use core::ffi::c_int;
 
-use super::fd::FileDesc;
+pub(crate) use hermit_abi as netc;
+
 use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::net::{Shutdown, SocketAddr};
 use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
+use crate::sys::fd::FileDesc;
+use crate::sys::net::{getsockopt, setsockopt, sockaddr_to_addr};
 use crate::sys::time::Instant;
-use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
+pub use crate::sys::{cvt, cvt_r};
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::Duration;
 use crate::{cmp, mem};
 
-#[allow(unused_extern_crates)]
-pub extern crate hermit_abi as netc;
-
-pub use crate::sys::{cvt, cvt_r};
-
+#[expect(non_camel_case_types)]
 pub type wrlen_t = usize;
 
 pub fn cvt_gai(err: i32) -> io::Result<()> {
diff --git a/library/std/src/sys/pal/solid/net.rs b/library/std/src/sys/net/connection/socket/solid.rs
index 5f6436807e2..f85ecbb883e 100644
--- a/library/std/src/sys/pal/solid/net.rs
+++ b/library/std/src/sys/net/connection/socket/solid.rs
@@ -1,24 +1,23 @@
 use libc::{c_int, c_void, size_t};
 
 use self::netc::{MSG_PEEK, sockaddr, socklen_t};
-use super::abi;
 use crate::ffi::CStr;
 use crate::io::{self, BorrowedBuf, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut};
 use crate::net::{Shutdown, SocketAddr};
 use crate::os::solid::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd};
-use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
+use crate::sys::abi;
+use crate::sys::net::{getsockopt, setsockopt, sockaddr_to_addr};
 use crate::sys_common::{FromInner, IntoInner};
 use crate::time::Duration;
 use crate::{cmp, mem, ptr, str};
 
 pub mod netc {
-    pub use super::super::abi::sockets::*;
+    pub use crate::sys::abi::sockets::*;
 }
 
+#[expect(non_camel_case_types)]
 pub type wrlen_t = size_t;
 
-const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
-
 const fn max_iov() -> usize {
     // Judging by the source code, it's unlimited, but specify a lower
     // value just in case.
@@ -78,7 +77,7 @@ fn last_error() -> io::Error {
     io::Error::from_raw_os_error(unsafe { netc::SOLID_NET_GetLastError() })
 }
 
-pub(super) fn error_name(er: abi::ER) -> Option<&'static str> {
+pub fn error_name(er: abi::ER) -> Option<&'static str> {
     unsafe { CStr::from_ptr(netc::strerror(er)) }.to_str().ok()
 }
 
@@ -87,7 +86,7 @@ pub fn is_interrupted(er: abi::ER) -> bool {
     er == netc::SOLID_NET_ERR_BASE - libc::EINTR
 }
 
-pub(super) fn decode_error_kind(er: abi::ER) -> ErrorKind {
+pub fn decode_error_kind(er: abi::ER) -> ErrorKind {
     let errno = netc::SOLID_NET_ERR_BASE - er;
     match errno as libc::c_int {
         libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
@@ -268,17 +267,6 @@ impl Socket {
         self.recv_from_with_flags(buf, MSG_PEEK)
     }
 
-    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
-        let ret = cvt(unsafe {
-            netc::write(
-                self.as_raw_fd(),
-                buf.as_ptr() as *const c_void,
-                cmp::min(buf.len(), READ_LIMIT),
-            )
-        })?;
-        Ok(ret as usize)
-    }
-
     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
         let ret = cvt(unsafe {
             netc::writev(
diff --git a/library/std/src/sys/net/connection/socket/tests.rs b/library/std/src/sys/net/connection/socket/tests.rs
new file mode 100644
index 00000000000..fc236b8027b
--- /dev/null
+++ b/library/std/src/sys/net/connection/socket/tests.rs
@@ -0,0 +1,19 @@
+use super::*;
+use crate::collections::HashMap;
+
+#[test]
+fn no_lookup_host_duplicates() {
+    let mut addrs = HashMap::new();
+    let lh = match LookupHost::try_from(("localhost", 0)) {
+        Ok(lh) => lh,
+        Err(e) => panic!("couldn't resolve `localhost`: {e}"),
+    };
+    for sa in lh {
+        *addrs.entry(sa).or_insert(0) += 1;
+    }
+    assert_eq!(
+        addrs.iter().filter(|&(_, &v)| v > 1).collect::<Vec<_>>(),
+        vec![],
+        "There should be no duplicate localhost entries"
+    );
+}
diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/net/connection/socket/unix.rs
index d73b9fd5eb8..da631605527 100644
--- a/library/std/src/sys/pal/unix/net.rs
+++ b/library/std/src/sys/net/connection/socket/unix.rs
@@ -5,8 +5,8 @@ use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::net::{Shutdown, SocketAddr};
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 use crate::sys::fd::FileDesc;
-use crate::sys::pal::unix::IsMinusOne;
-use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
+use crate::sys::net::{getsockopt, setsockopt, sockaddr_to_addr};
+use crate::sys::pal::IsMinusOne;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::{Duration, Instant};
 use crate::{cmp, mem};
@@ -19,11 +19,11 @@ cfg_if::cfg_if! {
     }
 }
 
-pub use crate::sys::{cvt, cvt_r};
+pub(crate) use libc as netc;
 
-#[allow(unused_extern_crates)]
-pub extern crate libc as netc;
+pub use crate::sys::{cvt, cvt_r};
 
+#[expect(non_camel_case_types)]
 pub type wrlen_t = size_t;
 
 pub struct Socket(FileDesc);
diff --git a/library/std/src/sys/pal/wasip2/net.rs b/library/std/src/sys/net/connection/socket/wasip2.rs
index f009a51821f..9d1c05a473e 100644
--- a/library/std/src/sys/pal/wasip2/net.rs
+++ b/library/std/src/sys/net/connection/socket/wasip2.rs
@@ -6,8 +6,8 @@ use crate::ffi::CStr;
 use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::net::{Shutdown, SocketAddr};
 use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::sys::net::{getsockopt, setsockopt, sockaddr_to_addr};
 use crate::sys::unsupported;
-use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::{Duration, Instant};
 use crate::{cmp, mem, str};
diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/net/connection/socket/windows.rs
index a92853c642c..80cf37eaf05 100644
--- a/library/std/src/sys/pal/windows/net.rs
+++ b/library/std/src/sys/net/connection/socket/windows.rs
@@ -9,7 +9,7 @@ use crate::os::windows::io::{
 };
 use crate::sync::OnceLock;
 use crate::sys::c;
-use crate::sys_common::{AsInner, FromInner, IntoInner, net};
+use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::Duration;
 use crate::{cmp, mem, ptr, sys};
 
@@ -110,6 +110,7 @@ pub mod netc {
     }
 }
 
+#[expect(missing_debug_implementations)]
 pub struct Socket(OwnedSocket);
 
 static WSA_CLEANUP: OnceLock<unsafe extern "system" fn() -> i32> = OnceLock::new();
@@ -400,12 +401,12 @@ impl Socket {
                 let error = unsafe { c::WSAGetLastError() };
 
                 if error == c::WSAESHUTDOWN {
-                    Ok((0, net::sockaddr_to_addr(&storage, addrlen as usize)?))
+                    Ok((0, super::sockaddr_to_addr(&storage, addrlen as usize)?))
                 } else {
                     Err(io::Error::from_raw_os_error(error))
                 }
             }
-            _ => Ok((result as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)),
+            _ => Ok((result as usize, super::sockaddr_to_addr(&storage, addrlen as usize)?)),
         }
     }
 
@@ -450,11 +451,11 @@ impl Socket {
             }
             None => 0,
         };
-        net::setsockopt(self, c::SOL_SOCKET, kind, timeout)
+        super::setsockopt(self, c::SOL_SOCKET, kind, timeout)
     }
 
     pub fn timeout(&self, kind: c_int) -> io::Result<Option<Duration>> {
-        let raw: u32 = net::getsockopt(self, c::SOL_SOCKET, kind)?;
+        let raw: u32 = super::getsockopt(self, c::SOL_SOCKET, kind)?;
         if raw == 0 {
             Ok(None)
         } else {
@@ -487,26 +488,26 @@ impl Socket {
             l_linger: linger.unwrap_or_default().as_secs() as c_ushort,
         };
 
-        net::setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger)
+        super::setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger)
     }
 
     pub fn linger(&self) -> io::Result<Option<Duration>> {
-        let val: c::LINGER = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?;
+        let val: c::LINGER = super::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?;
 
         Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
     }
 
     pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
-        net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL)
+        super::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL)
     }
 
     pub fn nodelay(&self) -> io::Result<bool> {
-        let raw: c::BOOL = net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?;
+        let raw: c::BOOL = super::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?;
         Ok(raw != 0)
     }
 
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        let raw: c_int = net::getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?;
+        let raw: c_int = super::getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?;
         if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
     }
 
diff --git a/library/std/src/sys/pal/unsupported/net.rs b/library/std/src/sys/net/connection/unsupported.rs
index 87e6106468f..87e6106468f 100644
--- a/library/std/src/sys/pal/unsupported/net.rs
+++ b/library/std/src/sys/net/connection/unsupported.rs
diff --git a/library/std/src/sys/pal/wasi/net.rs b/library/std/src/sys/net/connection/wasip1.rs
index a6486799828..27e3a528af4 100644
--- a/library/std/src/sys/pal/wasi/net.rs
+++ b/library/std/src/sys/net/connection/wasip1.rs
@@ -1,12 +1,11 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-use super::err2io;
-use super::fd::WasiFd;
 use crate::fmt;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
 use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
-use crate::sys::unsupported;
+use crate::sys::fd::WasiFd;
+use crate::sys::{err2io, unsupported};
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::Duration;
 
diff --git a/library/std/src/sys/pal/xous/net/dns.rs b/library/std/src/sys/net/connection/xous/dns.rs
index ff6e49ed2d4..ff6e49ed2d4 100644
--- a/library/std/src/sys/pal/xous/net/dns.rs
+++ b/library/std/src/sys/net/connection/xous/dns.rs
diff --git a/library/std/src/sys/pal/xous/net/mod.rs b/library/std/src/sys/net/connection/xous/mod.rs
index 3e18ed24208..3e18ed24208 100644
--- a/library/std/src/sys/pal/xous/net/mod.rs
+++ b/library/std/src/sys/net/connection/xous/mod.rs
diff --git a/library/std/src/sys/pal/xous/net/tcplistener.rs b/library/std/src/sys/net/connection/xous/tcplistener.rs
index 640a02a64f5..640a02a64f5 100644
--- a/library/std/src/sys/pal/xous/net/tcplistener.rs
+++ b/library/std/src/sys/net/connection/xous/tcplistener.rs
diff --git a/library/std/src/sys/pal/xous/net/tcpstream.rs b/library/std/src/sys/net/connection/xous/tcpstream.rs
index 572dd6b3b63..572dd6b3b63 100644
--- a/library/std/src/sys/pal/xous/net/tcpstream.rs
+++ b/library/std/src/sys/net/connection/xous/tcpstream.rs
diff --git a/library/std/src/sys/pal/xous/net/udp.rs b/library/std/src/sys/net/connection/xous/udp.rs
index 1b7ecac6d3a..1b7ecac6d3a 100644
--- a/library/std/src/sys/pal/xous/net/udp.rs
+++ b/library/std/src/sys/net/connection/xous/udp.rs
diff --git a/library/std/src/sys/net/mod.rs b/library/std/src/sys/net/mod.rs
new file mode 100644
index 00000000000..5aa197fbc0d
--- /dev/null
+++ b/library/std/src/sys/net/mod.rs
@@ -0,0 +1,36 @@
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        all(target_family = "unix", not(target_os = "l4re")),
+        target_os = "windows",
+        target_os = "hermit",
+        all(target_os = "wasi", target_env = "p2"),
+        target_os = "solid_asp3",
+    ))] {
+        mod connection {
+            mod socket;
+            pub use socket::*;
+        }
+    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+        mod connection {
+            mod sgx;
+            pub use sgx::*;
+        }
+    } else if #[cfg(all(target_os = "wasi", target_env = "p1"))] {
+        mod connection {
+            mod wasip1;
+            pub use wasip1::*;
+        }
+    } else if #[cfg(target_os = "xous")] {
+        mod connection {
+            mod xous;
+            pub use xous::*;
+        }
+    } else {
+        mod connection {
+            mod unsupported;
+            pub use unsupported::*;
+        }
+    }
+}
+
+pub use connection::*;
diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs
index d833c9d632c..032007aa4dc 100644
--- a/library/std/src/sys/pal/hermit/mod.rs
+++ b/library/std/src/sys/pal/hermit/mod.rs
@@ -24,7 +24,6 @@ pub mod fd;
 pub mod fs;
 pub mod futex;
 pub mod io;
-pub mod net;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs
index ce8a2fed4bc..0f5935d0c71 100644
--- a/library/std/src/sys/pal/sgx/mod.rs
+++ b/library/std/src/sys/pal/sgx/mod.rs
@@ -17,7 +17,6 @@ pub mod fs;
 #[path = "../unsupported/io.rs"]
 pub mod io;
 mod libunwind_integration;
-pub mod net;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
diff --git a/library/std/src/sys/pal/solid/error.rs b/library/std/src/sys/pal/solid/error.rs
index e092497856d..b399463c0c2 100644
--- a/library/std/src/sys/pal/solid/error.rs
+++ b/library/std/src/sys/pal/solid/error.rs
@@ -1,6 +1,7 @@
 pub use self::itron::error::{ItronError as SolidError, expect_success};
-use super::{abi, itron, net};
+use super::{abi, itron};
 use crate::io::ErrorKind;
+use crate::sys::net;
 
 /// Describe the specified SOLID error code. Returns `None` if it's an
 /// undefined error code.
diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs
index d41042be518..caf848a4e9b 100644
--- a/library/std/src/sys/pal/solid/mod.rs
+++ b/library/std/src/sys/pal/solid/mod.rs
@@ -24,7 +24,6 @@ pub mod env;
 pub(crate) mod error;
 pub mod fs;
 pub mod io;
-pub mod net;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
@@ -51,7 +50,7 @@ pub fn unsupported_err() -> crate::io::Error {
 
 #[inline]
 pub fn is_interrupted(code: i32) -> bool {
-    net::is_interrupted(code)
+    crate::sys::net::is_interrupted(code)
 }
 
 pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind {
diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs
index a9900f55b19..a9904e66664 100644
--- a/library/std/src/sys/pal/teeos/mod.rs
+++ b/library/std/src/sys/pal/teeos/mod.rs
@@ -15,7 +15,6 @@ pub mod env;
 pub mod fs;
 #[path = "../unsupported/io.rs"]
 pub mod io;
-pub mod net;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
diff --git a/library/std/src/sys/pal/teeos/net.rs b/library/std/src/sys/pal/teeos/net.rs
deleted file mode 100644
index fed95205027..00000000000
--- a/library/std/src/sys/pal/teeos/net.rs
+++ /dev/null
@@ -1,369 +0,0 @@
-use crate::fmt;
-use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
-use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
-use crate::sys::unsupported;
-use crate::time::Duration;
-
-pub struct TcpStream(!);
-
-impl TcpStream {
-    pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
-        unsupported()
-    }
-
-    pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
-        unsupported()
-    }
-
-    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-        self.0
-    }
-
-    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-        self.0
-    }
-
-    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
-        self.0
-    }
-
-    pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
-        self.0
-    }
-
-    pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        self.0
-    }
-
-    pub fn is_read_vectored(&self) -> bool {
-        self.0
-    }
-
-    pub fn write(&self, _: &[u8]) -> io::Result<usize> {
-        self.0
-    }
-
-    pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
-        self.0
-    }
-
-    pub fn is_write_vectored(&self) -> bool {
-        self.0
-    }
-
-    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        self.0
-    }
-
-    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        self.0
-    }
-
-    pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn duplicate(&self) -> io::Result<TcpStream> {
-        self.0
-    }
-
-    pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn linger(&self) -> io::Result<Option<Duration>> {
-        self.0
-    }
-
-    pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn nodelay(&self) -> io::Result<bool> {
-        self.0
-    }
-
-    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn ttl(&self) -> io::Result<u32> {
-        self.0
-    }
-
-    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        self.0
-    }
-
-    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-        self.0
-    }
-}
-
-impl fmt::Debug for TcpStream {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0
-    }
-}
-
-pub struct TcpListener(!);
-
-impl TcpListener {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
-        unsupported()
-    }
-
-    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        self.0
-    }
-
-    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
-        self.0
-    }
-
-    pub fn duplicate(&self) -> io::Result<TcpListener> {
-        self.0
-    }
-
-    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn ttl(&self) -> io::Result<u32> {
-        self.0
-    }
-
-    pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn only_v6(&self) -> io::Result<bool> {
-        self.0
-    }
-
-    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        self.0
-    }
-
-    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-        self.0
-    }
-}
-
-impl fmt::Debug for TcpListener {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0
-    }
-}
-
-pub struct UdpSocket(!);
-
-impl UdpSocket {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
-        unsupported()
-    }
-
-    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        self.0
-    }
-
-    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        self.0
-    }
-
-    pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-        self.0
-    }
-
-    pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-        self.0
-    }
-
-    pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
-        self.0
-    }
-
-    pub fn duplicate(&self) -> io::Result<UdpSocket> {
-        self.0
-    }
-
-    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-        self.0
-    }
-
-    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-        self.0
-    }
-
-    pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn broadcast(&self) -> io::Result<bool> {
-        self.0
-    }
-
-    pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
-        self.0
-    }
-
-    pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
-        self.0
-    }
-
-    pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
-        self.0
-    }
-
-    pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn ttl(&self) -> io::Result<u32> {
-        self.0
-    }
-
-    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        self.0
-    }
-
-    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-        self.0
-    }
-
-    pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
-        self.0
-    }
-
-    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
-        self.0
-    }
-
-    pub fn send(&self, _: &[u8]) -> io::Result<usize> {
-        self.0
-    }
-
-    pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
-        self.0
-    }
-}
-
-impl fmt::Debug for UdpSocket {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0
-    }
-}
-
-pub struct LookupHost(!);
-
-impl LookupHost {
-    pub fn port(&self) -> u16 {
-        self.0
-    }
-}
-
-impl Iterator for LookupHost {
-    type Item = SocketAddr;
-    fn next(&mut self) -> Option<SocketAddr> {
-        self.0
-    }
-}
-
-impl TryFrom<&str> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(_v: &str) -> io::Result<LookupHost> {
-        unsupported()
-    }
-}
-
-impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
-        unsupported()
-    }
-}
-
-#[allow(nonstandard_style)]
-pub mod netc {
-    pub const AF_INET: u8 = 0;
-    pub const AF_INET6: u8 = 1;
-    pub type sa_family_t = u8;
-
-    #[derive(Copy, Clone)]
-    pub struct in_addr {
-        pub s_addr: u32,
-    }
-
-    #[derive(Copy, Clone)]
-    pub struct sockaddr_in {
-        pub sin_family: sa_family_t,
-        pub sin_port: u16,
-        pub sin_addr: in_addr,
-    }
-
-    #[derive(Copy, Clone)]
-    pub struct in6_addr {
-        pub s6_addr: [u8; 16],
-    }
-
-    #[derive(Copy, Clone)]
-    pub struct sockaddr_in6 {
-        pub sin6_family: sa_family_t,
-        pub sin6_port: u16,
-        pub sin6_addr: in6_addr,
-        pub sin6_flowinfo: u32,
-        pub sin6_scope_id: u32,
-    }
-}
-
-pub type Socket = UdpSocket;
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index 111bed7a7eb..07025a304bf 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -19,8 +19,6 @@ pub mod fs;
 pub mod helpers;
 #[path = "../unsupported/io.rs"]
 pub mod io;
-#[path = "../unsupported/net.rs"]
-pub mod net;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
diff --git a/library/std/src/sys/pal/unix/l4re.rs b/library/std/src/sys/pal/unix/l4re.rs
deleted file mode 100644
index 37dd370c514..00000000000
--- a/library/std/src/sys/pal/unix/l4re.rs
+++ /dev/null
@@ -1,564 +0,0 @@
-macro_rules! unimpl {
-    () => {
-        return Err(io::const_error!(
-            io::ErrorKind::Unsupported,
-            "No networking available on L4Re.",
-        ));
-    };
-}
-
-pub mod net {
-    #![allow(warnings)]
-    use crate::fmt;
-    use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
-    use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
-    use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
-    use crate::sys::fd::FileDesc;
-    use crate::sys_common::{AsInner, FromInner, IntoInner};
-    use crate::time::Duration;
-
-    #[allow(unused_extern_crates)]
-    pub extern crate libc as netc;
-
-    pub struct Socket(FileDesc);
-    impl Socket {
-        pub fn new(_: &SocketAddr, _: libc::c_int) -> io::Result<Socket> {
-            unimpl!();
-        }
-
-        pub fn new_raw(_: libc::c_int, _: libc::c_int) -> io::Result<Socket> {
-            unimpl!();
-        }
-
-        pub fn new_pair(_: libc::c_int, _: libc::c_int) -> io::Result<(Socket, Socket)> {
-            unimpl!();
-        }
-
-        pub fn connect_timeout(&self, _: &SocketAddr, _: Duration) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn accept(
-            &self,
-            _: *mut libc::sockaddr,
-            _: *mut libc::socklen_t,
-        ) -> io::Result<Socket> {
-            unimpl!();
-        }
-
-        pub fn duplicate(&self) -> io::Result<Socket> {
-            unimpl!();
-        }
-
-        pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn read_buf(&self, _: BorrowedCursor<'_>) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn is_read_vectored(&self) -> bool {
-            false
-        }
-
-        pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-            unimpl!();
-        }
-
-        pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-            unimpl!();
-        }
-
-        pub fn write(&self, _: &[u8]) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn is_write_vectored(&self) -> bool {
-            false
-        }
-
-        pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn timeout(&self, _: libc::c_int) -> io::Result<Option<Duration>> {
-            unimpl!();
-        }
-
-        pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn linger(&self) -> io::Result<Option<Duration>> {
-            unimpl!();
-        }
-
-        pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn nodelay(&self) -> io::Result<bool> {
-            unimpl!();
-        }
-
-        pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-            unimpl!();
-        }
-
-        // This is used by sys_common code to abstract over Windows and Unix.
-        pub fn as_raw(&self) -> RawFd {
-            self.as_raw_fd()
-        }
-    }
-
-    impl AsInner<FileDesc> for Socket {
-        #[inline]
-        fn as_inner(&self) -> &FileDesc {
-            &self.0
-        }
-    }
-
-    impl FromInner<FileDesc> for Socket {
-        fn from_inner(file_desc: FileDesc) -> Socket {
-            Socket(file_desc)
-        }
-    }
-
-    impl IntoInner<FileDesc> for Socket {
-        fn into_inner(self) -> FileDesc {
-            self.0
-        }
-    }
-
-    impl AsFd for Socket {
-        fn as_fd(&self) -> BorrowedFd<'_> {
-            self.0.as_fd()
-        }
-    }
-
-    impl AsRawFd for Socket {
-        #[inline]
-        fn as_raw_fd(&self) -> RawFd {
-            self.0.as_raw_fd()
-        }
-    }
-
-    impl IntoRawFd for Socket {
-        fn into_raw_fd(self) -> RawFd {
-            self.0.into_raw_fd()
-        }
-    }
-
-    impl FromRawFd for Socket {
-        unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
-            Self(FromRawFd::from_raw_fd(raw_fd))
-        }
-    }
-
-    pub struct TcpStream {
-        inner: Socket,
-    }
-
-    impl TcpStream {
-        pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
-            unimpl!();
-        }
-
-        pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
-            unimpl!();
-        }
-
-        #[inline]
-        pub fn socket(&self) -> &Socket {
-            &self.inner
-        }
-
-        pub fn into_socket(self) -> Socket {
-            self.inner
-        }
-
-        pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-            unimpl!();
-        }
-
-        pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-            unimpl!();
-        }
-
-        pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn read_buf(&self, _: BorrowedCursor<'_>) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn is_read_vectored(&self) -> bool {
-            false
-        }
-
-        pub fn write(&self, _: &[u8]) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn is_write_vectored(&self) -> bool {
-            false
-        }
-
-        pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-            unimpl!();
-        }
-
-        pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-            unimpl!();
-        }
-
-        pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn duplicate(&self) -> io::Result<TcpStream> {
-            unimpl!();
-        }
-
-        pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn linger(&self) -> io::Result<Option<Duration>> {
-            unimpl!();
-        }
-
-        pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn nodelay(&self) -> io::Result<bool> {
-            unimpl!();
-        }
-
-        pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn ttl(&self) -> io::Result<u32> {
-            unimpl!();
-        }
-
-        pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-            unimpl!();
-        }
-
-        pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-            unimpl!();
-        }
-    }
-
-    impl FromInner<Socket> for TcpStream {
-        fn from_inner(socket: Socket) -> TcpStream {
-            TcpStream { inner: socket }
-        }
-    }
-
-    impl fmt::Debug for TcpStream {
-        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            write!(f, "No networking support available on L4Re")
-        }
-    }
-
-    pub struct TcpListener {
-        inner: Socket,
-    }
-
-    impl TcpListener {
-        pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
-            unimpl!();
-        }
-
-        #[inline]
-        pub fn socket(&self) -> &Socket {
-            &self.inner
-        }
-
-        pub fn into_socket(self) -> Socket {
-            self.inner
-        }
-
-        pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-            unimpl!();
-        }
-
-        pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
-            unimpl!();
-        }
-
-        pub fn duplicate(&self) -> io::Result<TcpListener> {
-            unimpl!();
-        }
-
-        pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn ttl(&self) -> io::Result<u32> {
-            unimpl!();
-        }
-
-        pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn only_v6(&self) -> io::Result<bool> {
-            unimpl!();
-        }
-
-        pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-            unimpl!();
-        }
-
-        pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-            unimpl!();
-        }
-    }
-
-    impl FromInner<Socket> for TcpListener {
-        fn from_inner(socket: Socket) -> TcpListener {
-            TcpListener { inner: socket }
-        }
-    }
-
-    impl fmt::Debug for TcpListener {
-        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            write!(f, "No networking support available on L4Re.")
-        }
-    }
-
-    pub struct UdpSocket {
-        inner: Socket,
-    }
-
-    impl UdpSocket {
-        pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
-            unimpl!();
-        }
-
-        #[inline]
-        pub fn socket(&self) -> &Socket {
-            &self.inner
-        }
-
-        pub fn into_socket(self) -> Socket {
-            self.inner
-        }
-
-        pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-            unimpl!();
-        }
-
-        pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-            unimpl!();
-        }
-
-        pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-            unimpl!();
-        }
-
-        pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-            unimpl!();
-        }
-
-        pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn duplicate(&self) -> io::Result<UdpSocket> {
-            unimpl!();
-        }
-
-        pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-            unimpl!();
-        }
-
-        pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-            unimpl!();
-        }
-
-        pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn broadcast(&self) -> io::Result<bool> {
-            unimpl!();
-        }
-
-        pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn multicast_loop_v4(&self) -> io::Result<bool> {
-            unimpl!();
-        }
-
-        pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
-            unimpl!();
-        }
-
-        pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn multicast_loop_v6(&self) -> io::Result<bool> {
-            unimpl!();
-        }
-
-        pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn ttl(&self) -> io::Result<u32> {
-            unimpl!();
-        }
-
-        pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-            unimpl!();
-        }
-
-        pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-            unimpl!();
-        }
-
-        pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn send(&self, _: &[u8]) -> io::Result<usize> {
-            unimpl!();
-        }
-
-        pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
-            unimpl!();
-        }
-    }
-
-    impl FromInner<Socket> for UdpSocket {
-        fn from_inner(socket: Socket) -> UdpSocket {
-            UdpSocket { inner: socket }
-        }
-    }
-
-    impl fmt::Debug for UdpSocket {
-        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            write!(f, "No networking support on L4Re available.")
-        }
-    }
-
-    pub struct LookupHost {
-        original: *mut libc::addrinfo,
-        cur: *mut libc::addrinfo,
-    }
-
-    impl Iterator for LookupHost {
-        type Item = SocketAddr;
-        fn next(&mut self) -> Option<SocketAddr> {
-            None
-        }
-    }
-
-    impl LookupHost {
-        pub fn port(&self) -> u16 {
-            0 // unimplemented
-        }
-    }
-
-    unsafe impl Sync for LookupHost {}
-    unsafe impl Send for LookupHost {}
-
-    impl TryFrom<&str> for LookupHost {
-        type Error = io::Error;
-
-        fn try_from(_v: &str) -> io::Result<LookupHost> {
-            unimpl!();
-        }
-    }
-
-    impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
-        type Error = io::Error;
-
-        fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
-            unimpl!();
-        }
-    }
-}
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index 3cc1cae8d00..6862399b942 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -14,14 +14,8 @@ pub mod futex;
 pub mod io;
 #[cfg(any(target_os = "linux", target_os = "android"))]
 pub mod kernel_copy;
-#[cfg(target_os = "l4re")]
-mod l4re;
 #[cfg(target_os = "linux")]
 pub mod linux;
-#[cfg(not(target_os = "l4re"))]
-pub mod net;
-#[cfg(target_os = "l4re")]
-pub use self::l4re::net;
 pub mod os;
 pub mod pipe;
 pub mod process;
diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs
index 01d516f7568..4941dd4918c 100644
--- a/library/std/src/sys/pal/unsupported/mod.rs
+++ b/library/std/src/sys/pal/unsupported/mod.rs
@@ -4,7 +4,6 @@ pub mod args;
 pub mod env;
 pub mod fs;
 pub mod io;
-pub mod net;
 pub mod os;
 pub mod pipe;
 pub mod process;
diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs
index 361802d101d..312ad28ab51 100644
--- a/library/std/src/sys/pal/wasi/mod.rs
+++ b/library/std/src/sys/pal/wasi/mod.rs
@@ -22,7 +22,6 @@ pub mod fs;
 pub mod futex;
 pub mod io;
 
-pub mod net;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
@@ -45,5 +44,4 @@ mod helpers;
 // import conflict rules. If we glob export `helpers` and `common` together,
 // then the compiler complains about conflicts.
 
-use helpers::err2io;
-pub use helpers::{abort_internal, decode_error_kind, is_interrupted};
+pub(crate) use helpers::{abort_internal, decode_error_kind, err2io, is_interrupted};
diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs
index 320712fdcc9..234e946d3b8 100644
--- a/library/std/src/sys/pal/wasip2/mod.rs
+++ b/library/std/src/sys/pal/wasip2/mod.rs
@@ -20,7 +20,6 @@ pub mod futex;
 #[path = "../wasi/io.rs"]
 pub mod io;
 
-pub mod net;
 #[path = "../wasi/os.rs"]
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs
index 41fe019f110..1280f353200 100644
--- a/library/std/src/sys/pal/wasm/mod.rs
+++ b/library/std/src/sys/pal/wasm/mod.rs
@@ -23,8 +23,6 @@ pub mod env;
 pub mod fs;
 #[path = "../unsupported/io.rs"]
 pub mod io;
-#[path = "../unsupported/net.rs"]
-pub mod net;
 #[path = "../unsupported/os.rs"]
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index 4282dbb5493..f9aa049ca9a 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -22,7 +22,6 @@ pub mod fs;
 pub mod futex;
 pub mod handle;
 pub mod io;
-pub mod net;
 pub mod os;
 pub mod pipe;
 pub mod process;
@@ -63,7 +62,7 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
 // SAFETY: must be called only once during runtime cleanup.
 // NOTE: this is not guaranteed to run, for example when the program aborts.
 pub unsafe fn cleanup() {
-    net::cleanup();
+    crate::sys::net::cleanup();
 }
 
 #[inline]
diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs
index a64cd068560..8ba2b6e2f20 100644
--- a/library/std/src/sys/pal/xous/mod.rs
+++ b/library/std/src/sys/pal/xous/mod.rs
@@ -7,7 +7,6 @@ pub mod env;
 pub mod fs;
 #[path = "../unsupported/io.rs"]
 pub mod io;
-pub mod net;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs
index 6ea05772029..9e9ae861070 100644
--- a/library/std/src/sys/pal/zkvm/mod.rs
+++ b/library/std/src/sys/pal/zkvm/mod.rs
@@ -18,8 +18,6 @@ pub mod env;
 pub mod fs;
 #[path = "../unsupported/io.rs"]
 pub mod io;
-#[path = "../unsupported/net.rs"]
-pub mod net;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;