Repository: bytecodealliance/wasmtime
Pull request #7489 (2023-11-06 19:11:09)

Enable CI fail-fast behavior for non-PR builds
On PRs it's helpful to see full failures if they arise, but for non-PRs they're typically in the background so continuing after a job fails isn't going to help much.

<!--
Please make sure you include the following information:

- If this work has been discussed elsewhere, please include a link to that
  conversation. If it was discussed in an issue, just mention "issue #...".

- Explain why this change is needed. If the details are in an issue already,
  this can be brief.

Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.html

Please ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->



Patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 280ceba43..5b306f43e 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -387,7 +387,7 @@ jobs:
     env:
       QEMU_BUILD_VERSION: 8.1.1
     strategy:
-      fail-fast: false
+      fail-fast: ${{ github.event_name != 'pull_request' }}
       matrix: ${{ fromJson(needs.determine.outputs.test-matrix) }}
     steps:
     - uses: actions/checkout@v3
@@ -673,7 +673,7 @@ jobs:
     name: Release build for ${{ matrix.build }}
     runs-on: ${{ matrix.os }}
     strategy:
-      fail-fast: false
+      fail-fast: ${{ github.event_name != 'pull_request' }}
       matrix: ${{ fromJson(needs.determine.outputs.build-matrix) }}
     steps:
     - uses: actions/checkout@v3
diff --git a/Cargo.lock b/Cargo.lock
index 1b8e40430..688c145b5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2638,7 +2638,7 @@ version = "0.0.0"
 dependencies = [
  "cargo_metadata",
  "heck",
- "wit-component",
+ "wit-component 0.18.0",
 ]
 
 [[package]]
@@ -3101,18 +3101,18 @@ checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
 
 [[package]]
 name = "wasm-encoder"
-version = "0.36.1"
+version = "0.36.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53ae0be20bf87918df4fa831bfbbd0b491d24aee407ed86360eae4c2c5608d38"
+checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421"
 dependencies = [
  "leb128",
 ]
 
 [[package]]
 name = "wasm-metadata"
-version = "0.10.10"
+version = "0.10.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5621910462c61a8efc3248fdfb1739bf649bb335b0df935c27b340418105f9d8"
+checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f"
 dependencies = [
  "anyhow",
  "indexmap 2.0.0",
@@ -3126,9 +3126,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-mutate"
-version = "0.2.39"
+version = "0.2.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b39266e421acd09370e738fc042a5224d0014036ed919e68f1dd9a98a9b28f5a"
+checksum = "49afec9e74f8dd90367c8f9b60440e6b84bdfd46e8ca133dd6a040f296bbc328"
 dependencies = [
  "egg",
  "log",
@@ -3140,9 +3140,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-smith"
-version = "0.12.22"
+version = "0.12.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39217efc459328aa5a29a5bbf792e76f1ae7ebeedbf8878f8320b6a0a6544b06"
+checksum = "426255ec37d1127b020492d957b1a48c0828e667ad2693d98af942e276cfbd86"
 dependencies = [
  "arbitrary",
  "flagset",
@@ -3192,9 +3192,9 @@ dependencies = [
 
 [[package]]
 name = "wasmparser"
-version = "0.116.0"
+version = "0.116.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53290b1276c5c2d47d694fb1a920538c01f51690e7e261acbe1d10c5fc306ea1"
+checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50"
 dependencies = [
  "indexmap 2.0.0",
  "semver",
@@ -3211,9 +3211,9 @@ dependencies = [
 
 [[package]]
 name = "wasmprinter"
-version = "0.2.71"
+version = "0.2.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f98260aa20f939518bcec1fac32c78898d5c68872e7363a4651f21f791b6c7e"
+checksum = "9aff4df0cdf1906ec040e97d78c3fc8fd26d3f8d70adaac81f07f80957b63b54"
 dependencies = [
  "anyhow",
  "wasmparser",
@@ -3388,7 +3388,7 @@ dependencies = [
  "wasmtime-wasi-nn",
  "wasmtime-wasi-threads",
  "wasmtime-wast",
- "wast 67.0.0",
+ "wast 67.0.1",
  "wat",
  "windows-sys",
 ]
@@ -3419,7 +3419,7 @@ dependencies = [
  "wasmtime",
  "wasmtime-component-util",
  "wasmtime-wit-bindgen",
- "wit-parser",
+ "wit-parser 0.13.0",
 ]
 
 [[package]]
@@ -3774,7 +3774,7 @@ dependencies = [
  "anyhow",
  "log",
  "wasmtime",
- "wast 67.0.0",
+ "wast 67.0.1",
 ]
 
 [[package]]
@@ -3799,7 +3799,7 @@ dependencies = [
  "anyhow",
  "heck",
  "indexmap 2.0.0",
- "wit-parser",
+ "wit-parser 0.13.0",
 ]
 
 [[package]]
@@ -3817,9 +3817,9 @@ dependencies = [
 
 [[package]]
 name = "wast"
-version = "67.0.0"
+version = "67.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36c2933efd77ff2398b83817a98984ffe4b67aefd9aa1d2c8e68e19b553f1c38"
+checksum = "a974d82fac092b5227c1663e16514e7a85f32014e22e6fdcb08b71aec9d3fb1e"
 dependencies = [
  "leb128",
  "memchr",
@@ -3829,11 +3829,11 @@ dependencies = [
 
 [[package]]
 name = "wat"
-version = "1.0.78"
+version = "1.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c02905d13751dcb18f4e19f489d37a1bf139f519feaeef28d072a41a78e69a74"
+checksum = "adb220934f92f8551144c0003d1bc57a060674c99139f45ed623fbbf6d9262e7"
 dependencies = [
- "wast 67.0.0",
+ "wast 67.0.1",
 ]
 
 [[package]]
@@ -4104,8 +4104,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c8bf1fddccaff31a1ad57432d8bfb7027a7e552969b6c68d6d8820dcf5c2371f"
 dependencies = [
  "anyhow",
- "wit-component",
- "wit-parser",
+ "wit-component 0.17.0",
+ "wit-parser 0.12.2",
 ]
 
 [[package]]
@@ -4118,7 +4118,7 @@ dependencies = [
  "heck",
  "wasm-metadata",
  "wit-bindgen-core",
- "wit-component",
+ "wit-component 0.17.0",
 ]
 
 [[package]]
@@ -4133,7 +4133,7 @@ dependencies = [
  "syn 2.0.29",
  "wit-bindgen-core",
  "wit-bindgen-rust",
- "wit-component",
+ "wit-component 0.17.0",
 ]
 
 [[package]]
@@ -4152,7 +4152,26 @@ dependencies = [
  "wasm-encoder",
  "wasm-metadata",
  "wasmparser",
- "wit-parser",
+ "wit-parser 0.12.2",
+]
+
+[[package]]
+name = "wit-component"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634d0371ac5e57e42991aa53f0d79e53e53484afbf54777a5347605b0b229b9d"
+dependencies = [
+ "anyhow",
+ "bitflags 2.4.1",
+ "indexmap 2.0.0",
+ "log",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "wasm-encoder",
+ "wasm-metadata",
+ "wasmparser",
+ "wit-parser 0.13.0",
 ]
 
 [[package]]
@@ -4172,6 +4191,23 @@ dependencies = [
  "unicode-xid",
 ]
 
+[[package]]
+name = "wit-parser"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15df6b7b28ce94b8be39d8df5cb21a08a4f3b9f33b631aedb4aa5776f785ead3"
+dependencies = [
+ "anyhow",
+ "id-arena",
+ "indexmap 2.0.0",
+ "log",
+ "semver",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "unicode-xid",
+]
+
 [[package]]
 name = "witx"
 version = "0.9.1"
diff --git a/Cargo.toml b/Cargo.toml
index f41e8d743..e13b6b7b0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -213,14 +213,14 @@ wit-bindgen = { version = "0.13.1", default-features = false }
 
 # wasm-tools family:
 wasmparser = "0.116.0"
-wat = "1.0.78"
-wast = "67.0.0"
-wasmprinter = "0.2.71"
-wasm-encoder = "0.36.1"
-wasm-smith = "0.12.22"
-wasm-mutate = "0.2.39"
-wit-parser = "0.12.2"
-wit-component = "0.17.0"
+wat = "1.0.79"
+wast = "67.0.1"
+wasmprinter = "0.2.72"
+wasm-encoder = "0.36.2"
+wasm-smith = "0.12.23"
+wasm-mutate = "0.2.40"
+wit-parser = "0.13.0"
+wit-component = "0.18.0"
 
 # Non-Bytecode Alliance maintained dependencies:
 # --------------------------
diff --git a/crates/wasi-http/wit/deps/sockets/ip-name-lookup.wit b/crates/wasi-http/wit/deps/sockets/ip-name-lookup.wit
index 5ffe2a217..270e70258 100644
--- a/crates/wasi-http/wit/deps/sockets/ip-name-lookup.wit
+++ b/crates/wasi-http/wit/deps/sockets/ip-name-lookup.wit
@@ -1,40 +1,30 @@
 
 interface ip-name-lookup {
     use wasi:io/poll@0.2.0-rc-2023-11-05.{pollable};
-    use network.{network, error-code, ip-address, ip-address-family};
+    use network.{network, error-code, ip-address};
 
 
     /// Resolve an internet host name to a list of IP addresses.
     ///
-    /// See the wasi-socket proposal README.md for a comparison with getaddrinfo.
-    ///
-    /// # Parameters
-    /// - `name`: The name to look up. IP addresses are not allowed. Unicode domain names are automatically converted
-    ///     to ASCII using IDNA encoding.
-    /// - `address-family`: If provided, limit the results to addresses of this specific address family.
-    /// - `include-unavailable`: When set to true, this function will also return addresses of which the runtime
-    ///   thinks (or knows) can't be connected to at the moment. For example, this will return IPv6 addresses on
-    ///   systems without an active IPv6 interface. Notes:
-    ///     - Even when no public IPv6 interfaces are present or active, names like "localhost" can still resolve to an IPv6 address.
-    ///     - Whatever is "available" or "unavailable" is volatile and can change everytime a network cable is unplugged.
+    /// Unicode domain names are automatically converted to ASCII using IDNA encoding.
+    /// If the input is an IP address string, the address is parsed and returned
+    /// as-is without making any external requests.
     ///
-    /// This function never blocks. It either immediately fails or immediately returns successfully with a `resolve-address-stream`
-    /// that can be used to (asynchronously) fetch the results.
+    /// See the wasi-socket proposal README.md for a comparison with getaddrinfo.
     ///
-    /// At the moment, the stream never completes successfully with 0 items. Ie. the first call
-    /// to `resolve-next-address` never returns `ok(none)`. This may change in the future.
+    /// This function never blocks. It either immediately fails or immediately
+    /// returns successfully with a `resolve-address-stream` that can be used
+    /// to (asynchronously) fetch the results.
     ///
     /// # Typical errors
-    /// - `invalid-argument`:     `name` is a syntactically invalid domain name.
-    /// - `invalid-argument`:     `name` is an IP address.
-    /// - `not-supported`:        The specified `address-family` is not supported. (EAI_FAMILY)
+    /// - `invalid-argument`: `name` is a syntactically invalid domain name or IP address.
     ///
     /// # References:
     /// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html>
     /// - <https://man7.org/linux/man-pages/man3/getaddrinfo.3.html>
     /// - <https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo>
     /// - <https://man.freebsd.org/cgi/man.cgi?query=getaddrinfo&sektion=3>
-    resolve-addresses: func(network: borrow<network>, name: string, address-family: option<ip-address-family>, include-unavailable: bool) -> result<resolve-address-stream, error-code>;
+    resolve-addresses: func(network: borrow<network>, name: string) -> result<resolve-address-stream, error-code>;
 
     resource resolve-address-stream {
         /// Returns the next address from the resolver.
diff --git a/crates/wasi/src/preview2/host/mod.rs b/crates/wasi/src/preview2/host/mod.rs
index 651d2cd38..7aa4a8741 100644
--- a/crates/wasi/src/preview2/host/mod.rs
+++ b/crates/wasi/src/preview2/host/mod.rs
@@ -4,7 +4,7 @@ mod exit;
 pub(crate) mod filesystem;
 mod instance_network;
 mod io;
-mod network;
+pub(crate) mod network;
 mod random;
 mod tcp;
 mod tcp_create_socket;
diff --git a/crates/wasi/src/preview2/host/network.rs b/crates/wasi/src/preview2/host/network.rs
index 5233149f4..ce6f2f155 100644
--- a/crates/wasi/src/preview2/host/network.rs
+++ b/crates/wasi/src/preview2/host/network.rs
@@ -1,7 +1,8 @@
 use crate::preview2::bindings::sockets::network::{
-    self, ErrorCode, IpAddressFamily, IpSocketAddress, Ipv4Address, Ipv4SocketAddress, Ipv6Address,
+    self, ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, Ipv4SocketAddress,
     Ipv6SocketAddress,
 };
+use crate::preview2::network::{from_ipv4_addr, from_ipv6_addr, to_ipv4_addr, to_ipv6_addr};
 use crate::preview2::{SocketError, WasiView};
 use rustix::io::Errno;
 use std::io;
@@ -104,6 +105,15 @@ impl From<Errno> for ErrorCode {
     }
 }
 
+impl From<std::net::IpAddr> for IpAddress {
+    fn from(addr: std::net::IpAddr) -> Self {
+        match addr {
+            std::net::IpAddr::V4(v4) => Self::Ipv4(from_ipv4_addr(v4)),
+            std::net::IpAddr::V6(v6) => Self::Ipv6(from_ipv6_addr(v6)),
+        }
+    }
+}
+
 impl From<IpSocketAddress> for std::net::SocketAddr {
     fn from(addr: IpSocketAddress) -> Self {
         match addr {
@@ -159,26 +169,6 @@ impl From<std::net::SocketAddrV6> for Ipv6SocketAddress {
     }
 }
 
-fn to_ipv4_addr(addr: Ipv4Address) -> std::net::Ipv4Addr {
-    let (x0, x1, x2, x3) = addr;
-    std::net::Ipv4Addr::new(x0, x1, x2, x3)
-}
-
-fn from_ipv4_addr(addr: std::net::Ipv4Addr) -> Ipv4Address {
-    let [x0, x1, x2, x3] = addr.octets();
-    (x0, x1, x2, x3)
-}
-
-fn to_ipv6_addr(addr: Ipv6Address) -> std::net::Ipv6Addr {
-    let (x0, x1, x2, x3, x4, x5, x6, x7) = addr;
-    std::net::Ipv6Addr::new(x0, x1, x2, x3, x4, x5, x6, x7)
-}
-
-fn from_ipv6_addr(addr: std::net::Ipv6Addr) -> Ipv6Address {
-    let [x0, x1, x2, x3, x4, x5, x6, x7] = addr.segments();
-    (x0, x1, x2, x3, x4, x5, x6, x7)
-}
-
 impl std::net::ToSocketAddrs for IpSocketAddress {
     type Iter = <std::net::SocketAddr as std::net::ToSocketAddrs>::Iter;
 
@@ -288,7 +278,7 @@ pub(crate) mod util {
     }
 
     // Can be removed once `IpAddr::to_canonical` becomes stable.
-    fn to_canonical(addr: &IpAddr) -> IpAddr {
+    pub fn to_canonical(addr: &IpAddr) -> IpAddr {
         match addr {
             IpAddr::V4(ipv4) => IpAddr::V4(*ipv4),
             IpAddr::V6(ipv6) => {
diff --git a/crates/wasi/src/preview2/ip_name_lookup.rs b/crates/wasi/src/preview2/ip_name_lookup.rs
index b832bd501..ab69f8f1b 100644
--- a/crates/wasi/src/preview2/ip_name_lookup.rs
+++ b/crates/wasi/src/preview2/ip_name_lookup.rs
@@ -1,14 +1,18 @@
 use crate::preview2::bindings::sockets::ip_name_lookup::{Host, HostResolveAddressStream};
-use crate::preview2::bindings::sockets::network::{ErrorCode, IpAddress, IpAddressFamily, Network};
+use crate::preview2::bindings::sockets::network::{ErrorCode, IpAddress, Network};
+use crate::preview2::host::network::util;
 use crate::preview2::poll::{subscribe, Pollable, Subscribe};
 use crate::preview2::{spawn_blocking, AbortOnDropJoinHandle, SocketError, WasiView};
 use anyhow::Result;
 use std::mem;
-use std::net::{SocketAddr, ToSocketAddrs};
+use std::net::{Ipv6Addr, ToSocketAddrs};
 use std::pin::Pin;
+use std::str::FromStr;
 use std::vec;
 use wasmtime::component::Resource;
 
+use super::network::{from_ipv4_addr, from_ipv6_addr};
+
 pub enum ResolveAddressStream {
     Waiting(AbortOnDropJoinHandle<Result<Vec<IpAddress>, SocketError>>),
     Done(Result<vec::IntoIter<IpAddress>, SocketError>),
@@ -20,60 +24,16 @@ impl<T: WasiView> Host for T {
         &mut self,
         network: Resource<Network>,
         name: String,
-        family: Option<IpAddressFamily>,
-        include_unavailable: bool,
     ) -> Result<Resource<ResolveAddressStream>, SocketError> {
         let network = self.table().get(&network)?;
 
-        // `Host::parse` serves us two functions:
-        // 1. validate the input is not an IP address,
-        // 2. convert unicode domains to punycode.
-        let name = match url::Host::parse(&name).map_err(|_| ErrorCode::InvalidArgument)? {
-            url::Host::Domain(name) => name,
-            url::Host::Ipv4(_) => return Err(ErrorCode::InvalidArgument.into()),
-            url::Host::Ipv6(_) => return Err(ErrorCode::InvalidArgument.into()),
-        };
+        let host = parse(&name)?;
 
         if !network.allow_ip_name_lookup {
             return Err(ErrorCode::PermanentResolverFailure.into());
         }
 
-        // ignored for now, should probably have a future PR to actually take
-        // this into account. This would require invoking `getaddrinfo` directly
-        // rather than using the standard library to do it for us.
-        let _ = include_unavailable;
-
-        // For now use the standard library to perform actual resolution through
-        // the usage of the `ToSocketAddrs` trait. This blocks the current
-        // thread, so use `spawn_blocking`. Finally note that this is only
-        // resolving names, not ports, so force the port to be 0.
-        let task = spawn_blocking(move || -> Result<Vec<_>, SocketError> {
-            let result = (name.as_str(), 0)
-                .to_socket_addrs()
-                .map_err(|_| ErrorCode::NameUnresolvable)?; // If/when we use `getaddrinfo` directly, map the error properly.
-            Ok(result
-                .filter_map(|addr| {
-                    // In lieu of preventing these addresses from being resolved
-                    // in the first place, filter them out here.
-                    match addr {
-                        SocketAddr::V4(addr) => match family {
-                            None | Some(IpAddressFamily::Ipv4) => {
-                                let [a, b, c, d] = addr.ip().octets();
-                                Some(IpAddress::Ipv4((a, b, c, d)))
-                            }
-                            Some(IpAddressFamily::Ipv6) => None,
-                        },
-                        SocketAddr::V6(addr) => match family {
-                            None | Some(IpAddressFamily::Ipv6) => {
-                                let [a, b, c, d, e, f, g, h] = addr.ip().segments();
-                                Some(IpAddress::Ipv6((a, b, c, d, e, f, g, h)))
-                            }
-                            Some(IpAddressFamily::Ipv4) => None,
-                        },
-                    }
-                })
-                .collect())
-        });
+        let task = spawn_blocking(move || blocking_resolve(&host));
         let resource = self.table_mut().push(ResolveAddressStream::Waiting(task))?;
         Ok(resource)
     }
@@ -126,3 +86,40 @@ impl Subscribe for ResolveAddressStream {
         }
     }
 }
+
+fn parse(name: &str) -> Result<url::Host, SocketError> {
+    // `url::Host::parse` serves us two functions:
+    // 1. validate the input is a valid domain name or IP,
+    // 2. convert unicode domains to punycode.
+    match url::Host::parse(&name) {
+        Ok(host) => Ok(host),
+
+        // `url::Host::parse` doesn't understand bare IPv6 addresses without [brackets]
+        Err(_) => {
+            if let Ok(addr) = Ipv6Addr::from_str(name) {
+                Ok(url::Host::Ipv6(addr))
+            } else {
+                Err(ErrorCode::InvalidArgument.into())
+            }
+        }
+    }
+}
+
+fn blocking_resolve(host: &url::Host) -> Result<Vec<IpAddress>, SocketError> {
+    match host {
+        url::Host::Ipv4(v4addr) => Ok(vec![IpAddress::Ipv4(from_ipv4_addr(*v4addr))]),
+        url::Host::Ipv6(v6addr) => Ok(vec![IpAddress::Ipv6(from_ipv6_addr(*v6addr))]),
+        url::Host::Domain(domain) => {
+            // For now use the standard library to perform actual resolution through
+            // the usage of the `ToSocketAddrs` trait. This is only
+            // resolving names, not ports, so force the port to be 0.
+            let addresses = (domain.as_str(), 0)
+                .to_socket_addrs()
+                .map_err(|_| ErrorCode::NameUnresolvable)? // If/when we use `getaddrinfo` directly, map the error properly.
+                .map(|addr| util::to_canonical(&addr.ip()).into())
+                .collect();
+
+            Ok(addresses)
+        }
+    }
+}
diff --git a/crates/wasi/src/preview2/network.rs b/crates/wasi/src/preview2/network.rs
index b3b7537b9..65c380bd1 100644
--- a/crates/wasi/src/preview2/network.rs
+++ b/crates/wasi/src/preview2/network.rs
@@ -1,3 +1,4 @@
+use crate::preview2::bindings::sockets::network::{Ipv4Address, Ipv6Address};
 use crate::preview2::bindings::wasi::sockets::network::ErrorCode;
 use crate::preview2::{TableError, TrappableError};
 use cap_std::net::Pool;
@@ -34,3 +35,23 @@ pub enum SocketAddressFamily {
     Ipv4,
     Ipv6 { v6only: bool },
 }
+
+pub(crate) fn to_ipv4_addr(addr: Ipv4Address) -> std::net::Ipv4Addr {
+    let (x0, x1, x2, x3) = addr;
+    std::net::Ipv4Addr::new(x0, x1, x2, x3)
+}
+
+pub(crate) fn from_ipv4_addr(addr: std::net::Ipv4Addr) -> Ipv4Address {
+    let [x0, x1, x2, x3] = addr.octets();
+    (x0, x1, x2, x3)
+}
+
+pub(crate) fn to_ipv6_addr(addr: Ipv6Address) -> std::net::Ipv6Addr {
+    let (x0, x1, x2, x3, x4, x5, x6, x7) = addr;
+    std::net::Ipv6Addr::new(x0, x1, x2, x3, x4, x5, x6, x7)
+}
+
+pub(crate) fn from_ipv6_addr(addr: std::net::Ipv6Addr) -> Ipv6Address {
+    let [x0, x1, x2, x3, x4, x5, x6, x7] = addr.segments();
+    (x0, x1, x2, x3, x4, x5, x6, x7)
+}
diff --git a/crates/wasi/wit/deps/sockets/ip-name-lookup.wit b/crates/wasi/wit/deps/sockets/ip-name-lookup.wit
index 5ffe2a217..270e70258 100644
--- a/crates/wasi/wit/deps/sockets/ip-name-lookup.wit
+++ b/crates/wasi/wit/deps/sockets/ip-name-lookup.wit
@@ -1,40 +1,30 @@
 
 interface ip-name-lookup {
     use wasi:io/poll@0.2.0-rc-2023-11-05.{pollable};
-    use network.{network, error-code, ip-address, ip-address-family};
+    use network.{network, error-code, ip-address};
 
 
     /// Resolve an internet host name to a list of IP addresses.
     ///
-    /// See the wasi-socket proposal README.md for a comparison with getaddrinfo.
-    ///
-    /// # Parameters
-    /// - `name`: The name to look up. IP addresses are not allowed. Unicode domain names are automatically converted
-    ///     to ASCII using IDNA encoding.
-    /// - `address-family`: If provided, limit the results to addresses of this specific address family.
-    /// - `include-unavailable`: When set to true, this function will also return addresses of which the runtime
-    ///   thinks (or knows) can't be connected to at the moment. For example, this will return IPv6 addresses on
-    ///   systems without an active IPv6 interface. Notes:
-    ///     - Even when no public IPv6 interfaces are present or active, names like "localhost" can still resolve to an IPv6 address.
-    ///     - Whatever is "available" or "unavailable" is volatile and can change everytime a network cable is unplugged.
+    /// Unicode domain names are automatically converted to ASCII using IDNA encoding.
+    /// If the input is an IP address string, the address is parsed and returned
+    /// as-is without making any external requests.
     ///
-    /// This function never blocks. It either immediately fails or immediately returns successfully with a `resolve-address-stream`
-    /// that can be used to (asynchronously) fetch the results.
+    /// See the wasi-socket proposal README.md for a comparison with getaddrinfo.
     ///
-    /// At the moment, the stream never completes successfully with 0 items. Ie. the first call
-    /// to `resolve-next-address` never returns `ok(none)`. This may change in the future.
+    /// This function never blocks. It either immediately fails or immediately
+    /// returns successfully with a `resolve-address-stream` that can be used
+    /// to (asynchronously) fetch the results.
     ///
     /// # Typical errors
-    /// - `invalid-argument`:     `name` is a syntactically invalid domain name.
-    /// - `invalid-argument`:     `name` is an IP address.
-    /// - `not-supported`:        The specified `address-family` is not supported. (EAI_FAMILY)
+    /// - `invalid-argument`: `name` is a syntactically invalid domain name or IP address.
     ///
     /// # References:
     /// - <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html>
     /// - <https://man7.org/linux/man-pages/man3/getaddrinfo.3.html>
     /// - <https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo>
     /// - <https://man.freebsd.org/cgi/man.cgi?query=getaddrinfo&sektion=3>
-    resolve-addresses: func(network: borrow<network>, name: string, address-family: option<ip-address-family>, include-unavailable: bool) -> result<resolve-address-stream, error-code>;
+    resolve-addresses: func(network: borrow<network>, name: string) -> result<resolve-address-stream, error-code>;
 
     resource resolve-address-stream {
         /// Returns the next address from the resolver.
diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock
index 0a856149d..cd6b492bb 100644
--- a/supply-chain/imports.lock
+++ b/supply-chain/imports.lock
@@ -1168,6 +1168,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-encoder]]
+version = "0.36.2"
+when = "2023-11-06"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasm-metadata]]
 version = "0.10.9"
 when = "2023-10-14"
@@ -1182,6 +1189,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-metadata]]
+version = "0.10.11"
+when = "2023-11-06"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasm-mutate]]
 version = "0.2.38"
 when = "2023-10-14"
@@ -1196,6 +1210,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-mutate]]
+version = "0.2.40"
+when = "2023-11-06"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasm-smith]]
 version = "0.12.21"
 when = "2023-10-14"
@@ -1210,6 +1231,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasm-smith]]
+version = "0.12.23"
+when = "2023-11-06"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasmparser]]
 version = "0.115.0"
 when = "2023-10-14"
@@ -1224,6 +1252,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasmparser]]
+version = "0.116.1"
+when = "2023-11-06"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasmprinter]]
 version = "0.2.70"
 when = "2023-10-14"
@@ -1238,6 +1273,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wasmprinter]]
+version = "0.2.72"
+when = "2023-11-06"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wasmtime]]
 version = "14.0.2"
 when = "2023-10-26"
@@ -1552,6 +1594,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wast]]
+version = "67.0.1"
+when = "2023-11-06"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wat]]
 version = "1.0.77"
 when = "2023-10-14"
@@ -1566,6 +1615,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wat]]
+version = "1.0.79"
+when = "2023-11-06"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wiggle]]
 version = "14.0.2"
 when = "2023-10-26"
@@ -1768,6 +1824,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wit-component]]
+version = "0.18.0"
+when = "2023-11-06"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[publisher.wit-parser]]
 version = "0.12.1"
 when = "2023-10-18"
@@ -1782,6 +1845,13 @@ user-id = 1
 user-login = "alexcrichton"
 user-name = "Alex Crichton"
 
+[[publisher.wit-parser]]
+version = "0.13.0"
+when = "2023-11-06"
+user-id = 1
+user-login = "alexcrichton"
+user-name = "Alex Crichton"
+
 [[audits.embark-studios.wildcard-audits.spdx]]
 who = "Jake Shadle <opensource@embark-studios.com>"
 criteria = "safe-to-deploy"


Test patch:
diff --git a/crates/test-programs/src/bin/preview2_ip_name_lookup.rs b/crates/test-programs/src/bin/preview2_ip_name_lookup.rs
index 29c851a44..dbad2e807 100644
--- a/crates/test-programs/src/bin/preview2_ip_name_lookup.rs
+++ b/crates/test-programs/src/bin/preview2_ip_name_lookup.rs
@@ -1,36 +1,70 @@
-use test_programs::wasi::clocks::*;
-use test_programs::wasi::io::*;
+use test_programs::wasi::sockets::network::{ErrorCode, IpAddress};
 use test_programs::wasi::sockets::*;
 
 fn main() {
-    let network = instance_network::instance_network();
+    // Valid domains
+    resolve("localhost").unwrap();
+    resolve("example.com").unwrap();
+    resolve("münchen.de").unwrap();
+
+    // Valid IP addresses
+    assert_eq!(resolve_one("0.0.0.0").unwrap(), IpAddress::IPV4_UNSPECIFIED);
+    assert_eq!(resolve_one("127.0.0.1").unwrap(), IpAddress::IPV4_LOOPBACK);
+    assert_eq!(
+        resolve_one("192.0.2.0").unwrap(),
+        IpAddress::Ipv4((192, 0, 2, 0))
+    );
+    assert_eq!(resolve_one("::").unwrap(), IpAddress::IPV6_UNSPECIFIED);
+    assert_eq!(resolve_one("::1").unwrap(), IpAddress::IPV6_LOOPBACK);
+    assert_eq!(resolve_one("[::]").unwrap(), IpAddress::IPV6_UNSPECIFIED);
+    assert_eq!(
+        resolve_one("2001:0db8:0:0:0:0:0:0").unwrap(),
+        IpAddress::Ipv6((0x2001, 0x0db8, 0, 0, 0, 0, 0, 0))
+    );
+    assert_eq!(
+        resolve_one("dead:beef::").unwrap(),
+        IpAddress::Ipv6((0xdead, 0xbeef, 0, 0, 0, 0, 0, 0))
+    );
+    assert_eq!(
+        resolve_one("dead:beef::0").unwrap(),
+        IpAddress::Ipv6((0xdead, 0xbeef, 0, 0, 0, 0, 0, 0))
+    );
+    assert_eq!(
+        resolve_one("DEAD:BEEF::0").unwrap(),
+        IpAddress::Ipv6((0xdead, 0xbeef, 0, 0, 0, 0, 0, 0))
+    );
 
-    let addresses =
-        ip_name_lookup::resolve_addresses(&network, "example.com", None, false).unwrap();
-    let pollable = addresses.subscribe();
-    pollable.block();
-    assert!(addresses.resolve_next_address().is_ok());
+    // Invalid inputs
+    assert_eq!(resolve("").unwrap_err(), ErrorCode::InvalidArgument);
+    assert_eq!(resolve(" ").unwrap_err(), ErrorCode::InvalidArgument);
+    assert_eq!(resolve("a.b<&>").unwrap_err(), ErrorCode::InvalidArgument);
+    assert_eq!(
+        resolve("127.0.0.1:80").unwrap_err(),
+        ErrorCode::InvalidArgument
+    );
+    assert_eq!(resolve("[::]:80").unwrap_err(), ErrorCode::InvalidArgument);
+    assert_eq!(
+        resolve("http://example.com/").unwrap_err(),
+        ErrorCode::InvalidArgument
+    );
+}
 
-    let result = ip_name_lookup::resolve_addresses(&network, "a.b<&>", None, false);
-    assert!(matches!(result, Err(network::ErrorCode::InvalidArgument)));
+fn resolve(name: &str) -> Result<Vec<IpAddress>, ErrorCode> {
+    let network = instance_network::instance_network();
 
-    // Try resolving a valid address and ensure that it eventually terminates.
-    // To help prevent this test from being flaky this additionally times out
-    // the resolution and allows errors.
-    let addresses = ip_name_lookup::resolve_addresses(&network, "github.com", None, false).unwrap();
-    let lookup = addresses.subscribe();
-    let timeout = monotonic_clock::subscribe_duration(1_000_000_000);
-    let ready = poll::poll(&[&lookup, &timeout]);
-    assert!(ready.len() > 0);
-    match ready[0] {
-        0 => loop {
-            match addresses.resolve_next_address() {
-                Ok(Some(_)) => {}
-                Ok(None) => break,
-                Err(_) => break,
-            }
-        },
-        1 => {}
-        _ => unreachable!(),
+    match network.blocking_resolve_addresses(name) {
+        // The following error codes signal that the input passed validation
+        // and a lookup was actually attempted, but failed. Ignore these to
+        // make the CI tests less flaky:
+        Err(
+            ErrorCode::NameUnresolvable
+            | ErrorCode::TemporaryResolverFailure
+            | ErrorCode::PermanentResolverFailure,
+        ) => Ok(vec![]),
+        r => r,
     }
 }
+
+fn resolve_one(name: &str) -> Result<IpAddress, ErrorCode> {
+    Ok(resolve(name)?.first().unwrap().to_owned())
+}
diff --git a/crates/test-programs/src/sockets.rs b/crates/test-programs/src/sockets.rs
index 55426cdf7..1d0e7f089 100644
--- a/crates/test-programs/src/sockets.rs
+++ b/crates/test-programs/src/sockets.rs
@@ -2,6 +2,7 @@ use crate::wasi::clocks::monotonic_clock;
 use crate::wasi::io::poll::{self, Pollable};
 use crate::wasi::io::streams::{InputStream, OutputStream, StreamError};
 use crate::wasi::sockets::instance_network;
+use crate::wasi::sockets::ip_name_lookup;
 use crate::wasi::sockets::network::{
     ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, Ipv4SocketAddress, Ipv6SocketAddress,
     Network,
@@ -53,6 +54,31 @@ impl Network {
     pub fn default() -> Network {
         instance_network::instance_network()
     }
+
+    pub fn blocking_resolve_addresses(&self, name: &str) -> Result<Vec<IpAddress>, ErrorCode> {
+        let stream = ip_name_lookup::resolve_addresses(&self, name)?;
+
+        let timeout = monotonic_clock::subscribe_duration(TIMEOUT_NS);
+        let pollable = stream.subscribe();
+
+        let mut addresses = vec![];
+
+        loop {
+            match stream.resolve_next_address() {
+                Ok(Some(addr)) => {
+                    addresses.push(addr);
+                }
+                Ok(None) => match addresses[..] {
+                    [] => return Err(ErrorCode::NameUnresolvable),
+                    _ => return Ok(addresses),
+                },
+                Err(ErrorCode::WouldBlock) => {
+                    pollable.wait_until(&timeout)?;
+                }
+                Err(err) => return Err(err),
+            }
+        }
+    }
 }
 
 impl TcpSocket {