fix(wasi): advertise the compiled smoltcp stack so subnet proxy can forward (#2734)

* fix(wasi): advertise the compiled smoltcp stack and keep ring out of the guest

A WASI guest has no OS TUN device, so the TCP subnet proxy can only forward
through the user-space stack. The capability probe in the WASI runtime only
set smoltcp_available under wasm-host-tunnel-outbound, so a plain core build
left force_smoltcp false and the proxy fell back to the kernel-listener path,
which rewrites the SYN onto a device that does not exist and lets every entry
expire as "syn nat entry expired".

- Add CoreInstanceHostConfig::set_smoltcp_stack and call it from the WASI
  runtime whenever the stack is compiled in. The setter only raises the flag,
  so the host-tunnel mode keeps working independently of the feature.
- wasi-crypto-offload no longer pulls ring-crypto: the host performs AEAD for
  the guest (easytier_host.crypto_aead_seal/open), and a software backend adds
  no value inside WASI.
- build-wasi-core.sh now builds with --no-default-features and an explicit
  list. endpoint-discovery was the only default that pulled rustls/ring; ring
  compiles C shims for wasm32-wasip1 that surface as env.ring_core_* imports,
  which the Go host cannot provide.

Covered by two unit tests for the setter.

* style(wasi): remove extra blank line from runtime module

Remove the extra blank line at the end of the WASI runtime module.
This restores the repository-wide cargo fmt check for PR #2734.

---------

Co-authored-by: 刘金发 <liujinfa9242@dingtalk.com>
Co-authored-by: KKRainbow <5665404+KKRainbow@users.noreply.github.com>
This commit is contained in:
Fa
2026-10-25 19:34:33 +08:00
committed by GitHub
co-authored by 刘金发 KKRainbow
parent 2eca40c56a
commit 79dd97dd7f
4 changed files with 46 additions and 2 deletions
+4 -1
View File
@@ -110,7 +110,10 @@ browser-config = ["config-write", "easytier-proto/api", "easytier-proto/json-rpc
chacha20 = ["dep:chacha20poly1305"]
openssl-crypto = ["dep:openssl"]
ring-crypto = ["dep:ring"]
wasi-crypto-offload = ["ring-crypto"]
# The WASI host performs AEAD for the guest (easytier_host.crypto_aead_seal/open),
# so the guest must not link a software backend: ring would emit env.ring_core_* imports
# that the host module cannot provide.
wasi-crypto-offload = []
config-write = []
endpoint-discovery = [
"dep:http-body-util",
+31
View File
@@ -92,6 +92,16 @@ impl Default for CoreInstanceHostConfig {
}
impl CoreInstanceHostConfig {
/// Record whether this host can serve the TCP subnet proxy from a user-space TCP stack.
///
/// Hosts without an OS TUN device (WASI guests, sandboxes) can only forward proxied TCP
/// through such a stack, so they must advertise it for the proxy runtime to pick that path.
/// `requires_smoltcp` is sticky: once the host needs the stack it keeps needing it.
pub fn set_smoltcp_stack(&mut self, available: bool) {
self.smoltcp_available = available;
self.requires_smoltcp |= available;
}
pub(crate) fn accepts_runtime_url(&self, url: &url::Url) -> bool {
!self.ignore_unsupported_config
|| self
@@ -765,3 +775,24 @@ data_compress_algo = "Zstd"
);
}
}
#[cfg(test)]
mod host_capability_tests {
use super::CoreInstanceHostConfig;
#[test]
fn set_smoltcp_stack_marks_the_host_as_capable_and_dependent() {
let mut config = CoreInstanceHostConfig::default();
config.set_smoltcp_stack(true);
assert!(config.smoltcp_available);
assert!(config.requires_smoltcp);
}
#[test]
fn set_smoltcp_stack_does_not_claim_a_missing_stack() {
let mut config = CoreInstanceHostConfig::default();
config.set_smoltcp_stack(false);
assert!(!config.smoltcp_available);
assert!(!config.requires_smoltcp);
}
}
+6
View File
@@ -152,6 +152,12 @@ pub(super) fn new_wasi_core_runtime(
adapters.config.ignore_unsupported_config = true;
adapters.config.endpoint_protocols = host_tunnel_schemes.to_vec();
}
// A WASI guest has no OS TUN, so the TCP subnet proxy can only forward through the
// user-space stack. Advertise it whenever it is compiled in; never clear the flag, since
// the host-tunnel mode above may rely on it independently of this feature.
if cfg!(feature = "proxy-smoltcp-stack") {
adapters.config.set_smoltcp_stack(true);
}
#[cfg(feature = "wasm-host-tunnel")]
#[cfg(not(feature = "wasm-host-tunnel-outbound"))]
let tunnel_ingress = crate::wasi::adapter::tunnel::WasiHostTunnelIngress::new(
+5 -1
View File
@@ -10,7 +10,10 @@ cd "$repository_root"
readonly target_dir="${CARGO_TARGET_DIR:-target}"
readonly raw_artifact="${target_dir}/wasm32-wasip1/release/easytier_core.wasm"
readonly artifact="${target_dir}/wasm32-wasip1/release/easytier_core_go_host.wasm"
readonly core_features="management-rpc,proxy-smoltcp-stack,ring-crypto,wasi-crypto-offload"
# The WASI host performs AEAD for the guest, and the guest has no TLS stack of its own, so the
# default feature set (endpoint-discovery -> rustls -> ring) must stay off: ring compiles C
# shims into wasm32-wasip1 that become env.ring_core_* imports, which the Go host cannot provide.
readonly core_features="management,proxy-smoltcp-stack,wasi-crypto-offload,aes-gcm,tcp-hole-punch"
sha256_file() {
if command -v sha256sum >/dev/null; then
@@ -120,6 +123,7 @@ if [[ "$version" != *"version ${binaryen_version} "* ]]; then
fi
cargo build --release --target wasm32-wasip1 -p easytier-core \
--no-default-features \
--features "$core_features"
optimized="${artifact}.wasm-opt.$$"