Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 20 additions & 21 deletions library/std/src/net/socket_addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ mod tests;
pub use core::net::{SocketAddr, SocketAddrV4, SocketAddrV6};

use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use crate::sys::net::LookupHost;
use crate::{io, iter, option, slice, vec};

/// A trait for objects which can be converted or resolved to one or more
Expand Down Expand Up @@ -188,15 +187,9 @@ impl ToSocketAddrs for (Ipv6Addr, u16) {
}
}

fn resolve_socket_addr(lh: LookupHost) -> io::Result<vec::IntoIter<SocketAddr>> {
let p = lh.port();
let v: Vec<_> = lh
.map(|mut a| {
a.set_port(p);
a
})
.collect();
Ok(v.into_iter())
fn lookup_host(host: &str, port: u16) -> io::Result<vec::IntoIter<SocketAddr>> {
let addrs = crate::sys::net::lookup_host(host, port)?;
Ok(Vec::from_iter(addrs).into_iter())
}

#[stable(feature = "rust1", since = "1.0.0")]
Expand All @@ -205,17 +198,14 @@ impl ToSocketAddrs for (&str, u16) {
fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
let (host, port) = *self;

// try to parse the host as a regular IP address first
if let Ok(addr) = host.parse::<Ipv4Addr>() {
let addr = SocketAddrV4::new(addr, port);
return Ok(vec![SocketAddr::V4(addr)].into_iter());
}
if let Ok(addr) = host.parse::<Ipv6Addr>() {
let addr = SocketAddrV6::new(addr, port, 0, 0);
return Ok(vec![SocketAddr::V6(addr)].into_iter());
// Try to parse the host as a regular IP address first
if let Ok(addr) = host.parse::<IpAddr>() {
let addr = SocketAddr::new(addr, port);
return Ok(vec![addr].into_iter());
}

resolve_socket_addr((host, port).try_into()?)
// Otherwise, make the system look it up.
lookup_host(host, port)
}
}

Expand All @@ -232,12 +222,21 @@ impl ToSocketAddrs for (String, u16) {
impl ToSocketAddrs for str {
type Iter = vec::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
// try to parse as a regular SocketAddr first
// Try to parse as a regular SocketAddr first
if let Ok(addr) = self.parse() {
return Ok(vec![addr].into_iter());
}

resolve_socket_addr(self.try_into()?)
// Otherwise, split the string by ':' and convert the second part to u16...
let Some((host, port_str)) = self.rsplit_once(':') else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid socket address"));
};
let Ok(port) = port_str.parse::<u16>() else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid port value"));
};

// ... and make the system look up the host.
lookup_host(host, port)
Comment on lines +230 to +239

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is bogus and breaks the x86_64-fortanix-unknown-sgx target (and the x86_64-unknown-linux-fortanixvme target, but that hasn't been upstreamed yet). If the string can't be parsed, this function needs to return a NonIpSockAddr error.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How so? The lookup_host function will reconstruct the exact same string, assuming that it can be parsed as a host:port pair.

@jethrogb jethrogb Feb 18, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assuming that it can be parsed as a host:port pair

That is the problem. Strings that can't be parsed like that need to be passed in the error type to the underlying PAL.

@joboet joboet Feb 18, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would you want that? No other platform supports those.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the underlying interface specification from the platform:

In keeping with the design goals for this specification, the
networking/socket interface doesn't use `sockaddr` types and doesn't
have a separate API for name resolution. Userspace can't be trusted to
do name resolution correctly, and even if it did, *userspace can't be
trusted to actually connect streams to the correct address* specified by
the enclave. Therefore, addresses specified should merely be treated as a
suggestion, and additional measures must be taken by an enclave to verify
the stream is connected to the correct peer, e.g. TLS.

The networking API works with strings as addresses. All byte buffers
representing network addresses should contain a valid UTF-8 string. The
enclave should panic if it is passed an invalid string by userspace. It is
suggested that userspace supports at least the following notations:

* `hostname:port-number` (e.g. `example.com:123`)
* `dotted-octet-ipv4-address:port-number` (e.g. `192.0.2.1:123`)
* `[ipv6-address]:port-number` (e.g. `[2001:db8::1]:123`)

Additionally, other forms may be accepted, for example service names:

* `fully-qualified-service-name` (e.g. `_example._tcp.example.com`)
* `address:service-name` (e.g. `address:example`)

https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#networking

}
}

Expand Down
29 changes: 5 additions & 24 deletions library/std/src/sys/net/connection/sgx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,35 +499,16 @@ impl fmt::Display for NonIpSockAddr {

pub struct LookupHost(!);

impl LookupHost {
fn new(host: String) -> io::Result<LookupHost> {
Err(io::Error::new(io::ErrorKind::Uncategorized, NonIpSockAddr { host }))
}

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> {
LookupHost::new(v.to_owned())
}
}

impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
type Error = io::Error;

fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
LookupHost::new(format!("{host}:{port}"))
}
pub fn lookup_host(host: &str, port: u16) -> io::Result<LookupHost> {
Err(io::Error::new(
io::ErrorKind::Uncategorized,
NonIpSockAddr { host: format!("{host}:{port}") },
))
Comment on lines +510 to +513

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I known that you've kept the old error, but shouldn't this return unsupported() instead?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the ErrorKind should probably be Unsupported. But we cannot replace the whole error with UNSUPPORTED_PLATFORM as SGX uses the error to smuggle the hostname through to the socket implementation (I know, it's bad).

}
58 changes: 15 additions & 43 deletions library/std/src/sys/net/connection/socket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ fn to_ipv6mr_interface(value: u32) -> crate::ffi::c_uint {
}

////////////////////////////////////////////////////////////////////////////////
// get_host_addresses
// lookup_host
////////////////////////////////////////////////////////////////////////////////

pub struct LookupHost {
Expand All @@ -267,12 +267,6 @@ pub struct LookupHost {
port: u16,
}

impl LookupHost {
pub fn port(&self) -> u16 {
self.port
}
}

impl Iterator for LookupHost {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> {
Expand All @@ -281,7 +275,10 @@ impl Iterator for LookupHost {
let cur = self.cur.as_ref()?;
self.cur = cur.ai_next;
match socket_addr_from_c(cur.ai_addr.cast(), cur.ai_addrlen as usize) {
Ok(addr) => return Some(addr),
Ok(mut addr) => {
addr.set_port(self.port);
return Some(addr);
}
Err(_) => continue,
}
}
Expand All @@ -298,42 +295,17 @@ impl Drop for LookupHost {
}
}

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)),
}
};
pub fn lookup_host(host: &str, port: 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 })
}

// 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 })
}
})
}
})
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/net/connection/socket/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::collections::HashMap;
#[test]
fn no_lookup_host_duplicates() {
let mut addrs = HashMap::new();
let lh = match LookupHost::try_from(("localhost", 0)) {
let lh = match lookup_host("localhost", 0) {
Ok(lh) => lh,
Err(e) => panic!("couldn't resolve `localhost`: {e}"),
};
Expand Down
22 changes: 2 additions & 20 deletions library/std/src/sys/net/connection/uefi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,31 +333,13 @@ impl fmt::Debug for UdpSocket {

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()
}
pub fn lookup_host(_host: &str, _port: u16) -> io::Result<LookupHost> {
unsupported()
}
22 changes: 2 additions & 20 deletions library/std/src/sys/net/connection/unsupported.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,31 +304,13 @@ impl fmt::Debug for UdpSocket {

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()
}
pub fn lookup_host(_host: &str, _port: u16) -> io::Result<LookupHost> {
unsupported()
}
22 changes: 2 additions & 20 deletions library/std/src/sys/net/connection/wasip1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,31 +477,13 @@ impl fmt::Debug for UdpSocket {

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<'a> TryFrom<&'a str> for LookupHost {
type Error = io::Error;

fn try_from(_v: &'a 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()
}
pub fn lookup_host(_host: &str, _port: u16) -> io::Result<LookupHost> {
unsupported()
}
45 changes: 2 additions & 43 deletions library/std/src/sys/net/connection/xous/dns.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
use core::convert::{TryFrom, TryInto};

use crate::io;
use crate::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use crate::os::xous::ffi::lend_mut;
use crate::os::xous::services::{DnsLendMut, dns_server};

pub struct DnsError {
#[allow(dead_code)]
pub code: u8,
}

#[repr(C, align(4096))]
struct LookupHostQuery([u8; 4096]);

Expand All @@ -20,12 +13,6 @@ pub struct LookupHost {
count: usize,
}

impl LookupHost {
pub fn port(&self) -> u16 {
self.port
}
}

impl Iterator for LookupHost {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> {
Expand Down Expand Up @@ -72,7 +59,7 @@ impl Iterator for LookupHost {
}
}

pub fn lookup(query: &str, port: u16) -> Result<LookupHost, DnsError> {
pub fn lookup_host(query: &str, port: u16) -> io::Result<LookupHost> {
let mut result = LookupHost { data: LookupHostQuery([0u8; 4096]), offset: 0, count: 0, port };

// Copy the query into the message that gets sent to the DNS server
Expand All @@ -89,7 +76,7 @@ pub fn lookup(query: &str, port: u16) -> Result<LookupHost, DnsError> {
)
.unwrap();
if result.data.0[0] != 0 {
return Err(DnsError { code: result.data.0[1] });
return Err(io::const_error!(io::ErrorKind::InvalidInput, "DNS failure"));
}
assert_eq!(result.offset, 0);
result.count = result.data.0[1] as usize;
Expand All @@ -98,31 +85,3 @@ pub fn lookup(query: &str, port: u16) -> Result<LookupHost, DnsError> {
result.offset = 2;
Ok(result)
}

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 TryFrom<(&str, u16)> for LookupHost {
type Error = io::Error;

fn try_from(v: (&str, u16)) -> io::Result<LookupHost> {
lookup(v.0, v.1).map_err(|_e| io::const_error!(io::ErrorKind::InvalidInput, "DNS failure"))
}
}
2 changes: 1 addition & 1 deletion library/std/src/sys/net/connection/xous/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ pub struct GetAddress {
raw: [u8; 4096],
}

pub use dns::LookupHost;
pub use dns::lookup_host;
Loading
Loading