Skip to content

Commit 207a01e

Browse files
committed
std: make address resolution weirdness local to SGX
1 parent 41f2b6b commit 207a01e

File tree

16 files changed

+276
-216
lines changed

16 files changed

+276
-216
lines changed

library/std/src/io/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ impl Error {
9595

9696
pub(crate) const ZERO_TIMEOUT: Self =
9797
const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout");
98+
99+
pub(crate) const NO_ADDRESSES: Self =
100+
const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses");
98101
}
99102

100103
#[stable(feature = "rust1", since = "1.0.0")]

library/std/src/net/mod.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ pub use self::tcp::IntoIncoming;
3434
pub use self::tcp::{Incoming, TcpListener, TcpStream};
3535
#[stable(feature = "rust1", since = "1.0.0")]
3636
pub use self::udp::UdpSocket;
37-
use crate::io::{self, ErrorKind};
3837

3938
mod ip_addr;
4039
mod socket_addr;
@@ -67,23 +66,3 @@ pub enum Shutdown {
6766
#[stable(feature = "rust1", since = "1.0.0")]
6867
Both,
6968
}
70-
71-
fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
72-
where
73-
F: FnMut(io::Result<&SocketAddr>) -> io::Result<T>,
74-
{
75-
let addrs = match addr.to_socket_addrs() {
76-
Ok(addrs) => addrs,
77-
Err(e) => return f(Err(e)),
78-
};
79-
let mut last_err = None;
80-
for addr in addrs {
81-
match f(Ok(&addr)) {
82-
Ok(l) => return Ok(l),
83-
Err(e) => last_err = Some(e),
84-
}
85-
}
86-
Err(last_err.unwrap_or_else(|| {
87-
io::const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses")
88-
}))
89-
}

library/std/src/net/tcp.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ impl TcpStream {
167167
/// ```
168168
#[stable(feature = "rust1", since = "1.0.0")]
169169
pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
170-
super::each_addr(addr, net_imp::TcpStream::connect).map(TcpStream)
170+
net_imp::TcpStream::connect(addr).map(TcpStream)
171171
}
172172

173173
/// Opens a TCP connection to a remote host with a timeout.
@@ -782,7 +782,7 @@ impl TcpListener {
782782
/// ```
783783
#[stable(feature = "rust1", since = "1.0.0")]
784784
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
785-
super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener)
785+
net_imp::TcpListener::bind(addr).map(TcpListener)
786786
}
787787

788788
/// Returns the local socket address of this listener.

library/std/src/net/tcp/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::io::prelude::*;
2-
use crate::io::{BorrowedBuf, IoSlice, IoSliceMut};
2+
use crate::io::{BorrowedBuf, ErrorKind, IoSlice, IoSliceMut};
33
use crate::mem::MaybeUninit;
44
use crate::net::test::{next_test_ip4, next_test_ip6};
55
use crate::net::*;

library/std/src/net/udp.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ impl UdpSocket {
120120
/// [`Ipv4Addr::UNSPECIFIED`] or [`Ipv6Addr::UNSPECIFIED`].
121121
#[stable(feature = "rust1", since = "1.0.0")]
122122
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
123-
super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket)
123+
net_imp::UdpSocket::bind(addr).map(UdpSocket)
124124
}
125125

126126
/// Receives a single datagram message on the socket. On success, returns the number
@@ -677,7 +677,7 @@ impl UdpSocket {
677677
/// on the platform.
678678
#[stable(feature = "net2_mutators", since = "1.9.0")]
679679
pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
680-
super::each_addr(addr, |addr| self.0.connect(addr))
680+
self.0.connect(addr)
681681
}
682682

683683
/// Sends data on the socket to the remote address to which it is connected.

library/std/src/net/udp/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::io::ErrorKind;
12
use crate::net::test::{compare_ignore_zoneid, next_test_ip4, next_test_ip6};
23
use crate::net::*;
34
use crate::sync::mpsc::channel;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
cfg_select! {
2+
any(
3+
all(target_family = "unix", not(target_os = "l4re")),
4+
target_os = "windows",
5+
target_os = "hermit",
6+
all(target_os = "wasi", target_env = "p2"),
7+
target_os = "solid_asp3",
8+
) => {
9+
mod socket;
10+
pub use socket::*;
11+
}
12+
all(target_vendor = "fortanix", target_env = "sgx") => {
13+
mod sgx;
14+
pub use sgx::*;
15+
}
16+
all(target_os = "wasi", target_env = "p1") => {
17+
mod wasip1;
18+
pub use wasip1::*;
19+
}
20+
target_os = "xous" => {
21+
mod xous;
22+
pub use xous::*;
23+
}
24+
target_os = "uefi" => {
25+
mod uefi;
26+
pub use uefi::*;
27+
}
28+
_ => {
29+
mod unsupported;
30+
pub use unsupported::*;
31+
}
32+
}
33+
34+
#[cfg_attr(
35+
// Make sure that this is used on some platforms at least.
36+
not(any(target_os = "linux", target_os = "windows")),
37+
allow(dead_code)
38+
)]
39+
fn each_addr<A: crate::net::ToSocketAddrs, F, T>(addr: A, mut f: F) -> crate::io::Result<T>
40+
where
41+
F: FnMut(&crate::net::SocketAddr) -> crate::io::Result<T>,
42+
{
43+
use crate::io::Error;
44+
45+
let mut last_err = None;
46+
for addr in addr.to_socket_addrs()? {
47+
match f(&addr) {
48+
Ok(l) => return Ok(l),
49+
Err(e) => last_err = Some(e),
50+
}
51+
}
52+
53+
match last_err {
54+
Some(err) => Err(err),
55+
None => Err(Error::NO_ADDRESSES),
56+
}
57+
}

library/std/src/sys/net/connection/sgx.rs

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
use crate::error;
2+
use crate::fmt::{self, Write};
13
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
24
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
35
use crate::sync::Arc;
46
use crate::sys::abi::usercalls;
57
use crate::sys::fd::FileDesc;
68
use crate::sys::{AsInner, FromInner, IntoInner, TryIntoInner, sgx_ineffective, unsupported};
79
use crate::time::Duration;
8-
use crate::{error, fmt};
910

1011
const DEFAULT_FAKE_TTL: u32 = 64;
1112

@@ -63,18 +64,52 @@ impl fmt::Debug for TcpStream {
6364
}
6465
}
6566

66-
fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result<String> {
67-
match result {
68-
Ok(saddr) => Ok(saddr.to_string()),
69-
// need to downcast twice because io::Error::into_inner doesn't return the original
70-
// value if the conversion fails
71-
Err(e) => {
72-
if e.get_ref().and_then(|e| e.downcast_ref::<NonIpSockAddr>()).is_some() {
73-
Ok(e.into_inner().unwrap().downcast::<NonIpSockAddr>().unwrap().host)
74-
} else {
75-
Err(e)
67+
/// Converts each address in `addr` into a hostname.
68+
///
69+
/// SGX doesn't support DNS resolution but rather accepts hostnames in
70+
/// the same place as socket addresses. So, to make e.g.
71+
/// ```rust
72+
/// TcpStream::connect("example.com:80")`
73+
/// ```
74+
/// work, the DNS lookup returns a special error (`NonIpSockAddr`) instead,
75+
/// which contains the hostname being looked up. When `.to_socket_addrs()`
76+
/// fails, we inspect the error and try recover the hostname from it. If that
77+
/// succeeds, we thus continue with the hostname.
78+
///
79+
/// This is a terrible hack and leads to buggy code. For instance, when users
80+
/// use the result of `.to_socket_addrs()` in their own `ToSocketAddrs`
81+
/// implementation to select from a list of possible URLs, the only URL used
82+
/// will be that of the last item tried.
83+
// FIXME: This is a terrible, terrible hack. Fixing this requires Fortanix to
84+
// add a method for resolving addresses.
85+
fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
86+
where
87+
F: FnMut(&str) -> io::Result<T>,
88+
{
89+
match addr.to_socket_addrs() {
90+
Ok(addrs) => {
91+
let mut last_err = None;
92+
let mut encoded = String::new();
93+
for addr in addrs {
94+
// Format the IP address as a string, reusing the buffer.
95+
encoded.clear();
96+
write!(encoded, "{}", &addr).unwrap();
97+
98+
match f(&encoded) {
99+
Ok(val) => return Ok(val),
100+
Err(err) => last_err = Some(err),
101+
}
102+
}
103+
104+
match last_err {
105+
Some(err) => Err(err),
106+
None => Err(io::Error::NO_ADDRESSES),
76107
}
77108
}
109+
Err(err) => match err.get_ref().and_then(|e| e.downcast_ref::<NonIpSockAddr>()) {
110+
Some(NonIpSockAddr { host }) => f(host),
111+
None => Err(err),
112+
},
78113
}
79114
}
80115

@@ -86,17 +121,18 @@ fn addr_to_sockaddr(addr: Option<&str>) -> io::Result<SocketAddr> {
86121
}
87122

88123
impl TcpStream {
89-
pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
90-
let addr = io_err_to_addr(addr)?;
91-
let (fd, local_addr, peer_addr) = usercalls::connect_stream(&addr)?;
92-
Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) })
124+
pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
125+
each_addr(addr, |addr| {
126+
let (fd, local_addr, peer_addr) = usercalls::connect_stream(addr)?;
127+
Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) })
128+
})
93129
}
94130

95131
pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result<TcpStream> {
96132
if dur == Duration::default() {
97133
return Err(io::Error::ZERO_TIMEOUT);
98134
}
99-
Self::connect(Ok(addr)) // FIXME: ignoring timeout
135+
Self::connect(addr) // FIXME: ignoring timeout
100136
}
101137

102138
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
@@ -247,10 +283,11 @@ impl fmt::Debug for TcpListener {
247283
}
248284

249285
impl TcpListener {
250-
pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
251-
let addr = io_err_to_addr(addr)?;
252-
let (fd, local_addr) = usercalls::bind_stream(&addr)?;
253-
Ok(TcpListener { inner: Socket::new(fd, local_addr) })
286+
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
287+
each_addr(addr, |addr| {
288+
let (fd, local_addr) = usercalls::bind_stream(addr)?;
289+
Ok(TcpListener { inner: Socket::new(fd, local_addr) })
290+
})
254291
}
255292

256293
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
@@ -316,7 +353,7 @@ impl FromInner<Socket> for TcpListener {
316353
pub struct UdpSocket(!);
317354

318355
impl UdpSocket {
319-
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
356+
pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<UdpSocket> {
320357
unsupported()
321358
}
322359

@@ -436,7 +473,7 @@ impl UdpSocket {
436473
self.0
437474
}
438475

439-
pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
476+
pub fn connect<A: ToSocketAddrs>(&self, _: A) -> io::Result<()> {
440477
self.0
441478
}
442479
}

0 commit comments

Comments
 (0)