From 98f8c8e46872f0e347ff80d687b8a189089827d1 Mon Sep 17 00:00:00 2001 From: Martin Raszyk Date: Fri, 20 Dec 2024 13:39:56 +0100 Subject: [PATCH 1/2] fix: bind to [::1] per default instead of 127.0.0.1 in PocketIC --- packages/pocket-ic/BUILD.bazel | 9 --------- packages/pocket-ic/HOWTO.md | 4 ++-- packages/pocket-ic/src/lib.rs | 2 +- rs/pocket_ic_server/BUILD.bazel | 14 -------------- rs/pocket_ic_server/CHANGELOG.md | 3 +++ rs/pocket_ic_server/src/main.rs | 4 ++-- rs/pocket_ic_server/src/state_api/canister_id.rs | 11 ++++++++--- rs/pocket_ic_server/src/state_api/state.rs | 9 +++++---- .../tests/bitcoin_integration_tests.rs | 6 +++--- rs/pocket_ic_server/tests/test.rs | 16 ++++++++-------- 10 files changed, 32 insertions(+), 46 deletions(-) diff --git a/packages/pocket-ic/BUILD.bazel b/packages/pocket-ic/BUILD.bazel index 56cbb3fed7e..2368533d235 100644 --- a/packages/pocket-ic/BUILD.bazel +++ b/packages/pocket-ic/BUILD.bazel @@ -87,9 +87,6 @@ rust_test_suite( proc_macro_deps = MACRO_DEPENDENCIES, tags = [ "cpu:16", - # TODO: remove 'requires-network' tag when the root cause for sporadic error below on Apple Silicon is identified and fixed. - # Failed to crate http gateway: Failed to bind to address 127.0.0.1:0: Operation not permitted (os error 1) - "requires-network", "test_macos", ], deps = [":pocket-ic"] + DEPENDENCIES + TEST_DEPENDENCIES, @@ -110,9 +107,6 @@ rust_test_suite( flaky = False, proc_macro_deps = MACRO_DEPENDENCIES, tags = [ - # TODO: remove 'requires-network' tag when the root cause for sporadic error below on Apple Silicon is identified and fixed. - # Failed to crate http gateway: Failed to bind to address 127.0.0.1:0: Operation not permitted (os error 1) - "requires-network", "test_macos", ], deps = [":pocket-ic"] + DEPENDENCIES + TEST_DEPENDENCIES, @@ -136,9 +130,6 @@ rust_test_suite( proc_macro_deps = MACRO_DEPENDENCIES, tags = [ "cpu:16", - # TODO: remove 'requires-network' tag when the root cause for sporadic error below on Apple Silicon is identified and fixed. - # Failed to crate http gateway: Failed to bind to address 127.0.0.1:0: Operation not permitted (os error 1) - "requires-network", "test_macos", ], deps = [":pocket-ic"] + DEPENDENCIES + TEST_DEPENDENCIES, diff --git a/packages/pocket-ic/HOWTO.md b/packages/pocket-ic/HOWTO.md index e1244a3cfcf..bddf365a9eb 100644 --- a/packages/pocket-ic/HOWTO.md +++ b/packages/pocket-ic/HOWTO.md @@ -538,7 +538,7 @@ Now we create a PocketIC instance configured with the Bitcoin subnet and the `bi .with_ii_subnet() // to have tECDSA keys available .with_application_subnet() // to deploy the test dapp .with_bitcoind_addr(SocketAddr::new( - IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), + IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 18444, )) .build(); @@ -589,7 +589,7 @@ To mine blocks with rewards credited to a given `bitcoin_address: String`, you c ```rust use bitcoincore_rpc::{bitcoin::Address, Auth, Client, RpcApi}; let btc_rpc = Client::new( - "http://127.0.0.1:18443", + "http://[::1]:18443", Auth::UserPass( "ic-btc-integration".to_string(), "QPQiNaph19FqUsCrBRN0FII7lyM26B51fAMeBQzCb-E=".to_string(), diff --git a/packages/pocket-ic/src/lib.rs b/packages/pocket-ic/src/lib.rs index e647de89523..5ed366b42c7 100644 --- a/packages/pocket-ic/src/lib.rs +++ b/packages/pocket-ic/src/lib.rs @@ -81,7 +81,7 @@ const EXPECTED_SERVER_VERSION: &str = "pocket-ic-server 7.0.0"; // the default timeout of a PocketIC operation const DEFAULT_MAX_REQUEST_TIME_MS: u64 = 300_000; -const LOCALHOST: &str = "127.0.0.1"; +const LOCALHOST: &str = "[::1]"; pub struct PocketIcBuilder { config: Option, diff --git a/rs/pocket_ic_server/BUILD.bazel b/rs/pocket_ic_server/BUILD.bazel index d0f74e8c21d..875ac04e26d 100644 --- a/rs/pocket_ic_server/BUILD.bazel +++ b/rs/pocket_ic_server/BUILD.bazel @@ -189,17 +189,6 @@ rust_test( }, tags = [ "cpu:8", - # TODO: remove 'requires-network' tag when the root cause for sporadic error below on Apple Silicon is identified and fixed. - # ---- test_http_gateway stdout ---- - # thread 'test_http_gateway' panicked at rs/pocket_ic_server/tests/test.rs:383:48: - # called `Result::unwrap()` on an `Err` value: reqwest::Error { - # kind: Request, url: "http://7tjcv-pp777-77776-qaaaa-cai.raw.localhost:49380/", - # source: hyper_util::client::legacy::Error( - # Connect, - # ConnectError("tcp connect error", Os { code: 1, kind: PermissionDenied, message: "Operation not permitted" }) - # ) - # } - "requires-network", "test_macos", ], deps = TEST_DEPENDENCIES, @@ -252,9 +241,6 @@ rust_test( "SSL_CERT_FILE": "$(rootpath @mozilla_root_ca_store//file)", }, tags = [ - # TODO: remove 'requires-network' tag when the root cause for sporadic error below on Apple Silicon is identified and fixed. - # Failed to crate http gateway: Failed to bind to address 127.0.0.1:0: Operation not permitted (os error 1) - "requires-network", "test_macos", ], deps = TEST_DEPENDENCIES, diff --git a/rs/pocket_ic_server/CHANGELOG.md b/rs/pocket_ic_server/CHANGELOG.md index 43ec593bfc2..506c4a8e85a 100644 --- a/rs/pocket_ic_server/CHANGELOG.md +++ b/rs/pocket_ic_server/CHANGELOG.md @@ -14,6 +14,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - New endpoint `/instances//read/ingress_status` to fetch the status of an update call submitted through an ingress message. +### Changed +- The default IP address to which the PocketIC server and HTTP gateway bind is [::1] instead of 127.0.0.1. + ### Fixed - Canisters created via `provisional_create_canister_with_cycles` with the management canister ID as the effective canister ID are created on an arbitrary subnet. diff --git a/rs/pocket_ic_server/src/main.rs b/rs/pocket_ic_server/src/main.rs index 9911af56018..801183fa782 100644 --- a/rs/pocket_ic_server/src/main.rs +++ b/rs/pocket_ic_server/src/main.rs @@ -56,7 +56,7 @@ const LOG_DIR_LEVELS_ENV_NAME: &str = "POCKET_IC_LOG_DIR_LEVELS"; #[derive(Parser)] #[clap(version = "7.0.0")] struct Args { - /// The IP address to which the PocketIC server should bind (defaults to 127.0.0.1) + /// The IP address to which the PocketIC server should bind (defaults to [::1]) #[clap(long, short)] ip_addr: Option, /// Log levels for PocketIC server logs (defaults to `pocket_ic_server=info,tower_http=info,axum::rejection=trace`). @@ -122,7 +122,7 @@ async fn start(runtime: Arc) { None }; - let ip_addr = args.ip_addr.unwrap_or("127.0.0.1".to_string()); + let ip_addr = args.ip_addr.unwrap_or("[::1]".to_string()); let addr = format!("{}:{}", ip_addr, args.port); let listener = std::net::TcpListener::bind(addr.clone()) .unwrap_or_else(|_| panic!("Failed to bind PocketIC server to address {}", addr)); diff --git a/rs/pocket_ic_server/src/state_api/canister_id.rs b/rs/pocket_ic_server/src/state_api/canister_id.rs index 433781f0756..9356cae6ff1 100644 --- a/rs/pocket_ic_server/src/state_api/canister_id.rs +++ b/rs/pocket_ic_server/src/state_api/canister_id.rs @@ -2,13 +2,14 @@ use crate::state_api::state::HandlerState; use async_trait::async_trait; use axum::extract::FromRequestParts; use candid::Principal; -use fqdn::{fqdn, Fqdn, FQDN}; +use fqdn::{Fqdn, FQDN}; use hyper::{ header::{HOST, REFERER}, http::request::Parts, Uri, }; use std::collections::BTreeMap; +use std::str::FromStr; use std::sync::Arc; // ADAPTED from ic-gateway @@ -189,8 +190,10 @@ impl FromRequestParts for HostHeader { .rsplit_once(':') .map(|(host, _port)| host) .unwrap_or(host); + let fqdn = + FQDN::from_str(host).map_err(|_| "Could not parse domain name from Host header")?; resolver - .resolve_domain(&fqdn!(host)) + .resolve_domain(&fqdn) .map(|d| d.canister_id) .ok_or(BAD_HOST)? .ok_or(BAD_HOST) @@ -228,8 +231,10 @@ impl FromRequestParts for RefererHeaderHost { let referer = referer.to_str().map_err(|_| BAD_REFERER)?; let referer: Uri = referer.parse().map_err(|_| BAD_REFERER)?; let referer = referer.authority().ok_or(BAD_REFERER)?; + let fqdn = FQDN::from_str(referer.host()) + .map_err(|_| "Could not parse domain name from Referer header")?; resolver - .resolve_domain(&fqdn!(referer.host())) + .resolve_domain(&fqdn) .map(|d| d.canister_id) .ok_or(BAD_REFERER)? .ok_or(BAD_REFERER) diff --git a/rs/pocket_ic_server/src/state_api/state.rs b/rs/pocket_ic_server/src/state_api/state.rs index f3d7a2311be..5a947611417 100644 --- a/rs/pocket_ic_server/src/state_api/state.rs +++ b/rs/pocket_ic_server/src/state_api/state.rs @@ -18,7 +18,7 @@ use axum::{ use axum_server::tls_rustls::RustlsConfig; use axum_server::Handle; use base64; -use fqdn::{fqdn, FQDN}; +use fqdn::FQDN; use futures::future::Shared; use http::{ header::{ @@ -810,7 +810,7 @@ impl ApiState { let ip_addr = http_gateway_config .ip_addr .clone() - .unwrap_or("127.0.0.1".to_string()); + .unwrap_or("[::1]".to_string()); let port = http_gateway_config.port.unwrap_or_default(); let addr = format!("{}:{}", ip_addr, port); let listener = std::net::TcpListener::bind(&addr) @@ -844,8 +844,9 @@ impl ApiState { .clone() .unwrap_or(vec!["localhost".to_string()]) .iter() - .map(|d| fqdn!(d)) - .collect(); + .map(|d| FQDN::from_str(d)) + .collect::, _>>() + .map_err(|e| e.to_string())?; spawn(async move { let http_gateway_client = ic_http_gateway::HttpGatewayClientBuilder::new() .with_agent(agent) diff --git a/rs/pocket_ic_server/tests/bitcoin_integration_tests.rs b/rs/pocket_ic_server/tests/bitcoin_integration_tests.rs index 59a97ab7dba..d5b1f5c7771 100644 --- a/rs/pocket_ic_server/tests/bitcoin_integration_tests.rs +++ b/rs/pocket_ic_server/tests/bitcoin_integration_tests.rs @@ -6,7 +6,7 @@ use ic_nns_constants::ROOT_CANISTER_ID; use pocket_ic::{update_candid, PocketIc, PocketIcBuilder}; use std::fs::{create_dir, File}; use std::io::Write; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use std::net::{IpAddr, Ipv6Addr, SocketAddr}; use std::process::Command; use std::str::FromStr; use std::time::SystemTime; @@ -105,7 +105,7 @@ rpcauth=ic-btc-integration:cdf2741387f3a12438f69092f0fdad8e$62081498c98bee09a0dc .with_ii_subnet() .with_application_subnet() .with_bitcoind_addr(SocketAddr::new( - IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), + IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 18444, )) .build(); @@ -130,7 +130,7 @@ rpcauth=ic-btc-integration:cdf2741387f3a12438f69092f0fdad8e$62081498c98bee09a0dc .0; let btc_rpc = Client::new( - "http://127.0.0.1:18443", + "http://[::1]:18443", Auth::UserPass( "ic-btc-integration".to_string(), "QPQiNaph19FqUsCrBRN0FII7lyM26B51fAMeBQzCb-E=".to_string(), diff --git a/rs/pocket_ic_server/tests/test.rs b/rs/pocket_ic_server/tests/test.rs index 1abd4e912e5..b6fcabc4108 100644 --- a/rs/pocket_ic_server/tests/test.rs +++ b/rs/pocket_ic_server/tests/test.rs @@ -25,13 +25,13 @@ use reqwest::{StatusCode, Url}; use slog::Level; use std::io::Read; use std::io::Write; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use std::net::{IpAddr, Ipv6Addr, SocketAddr}; use std::path::PathBuf; use std::process::{Child, Command}; use std::time::Duration; use tempfile::{NamedTempFile, TempDir}; -pub const LOCALHOST: &str = "127.0.0.1"; +pub const LOCALHOST: &str = "[::1]"; fn start_server_helper( test_driver_pid: Option, @@ -290,7 +290,7 @@ async fn test_gateway(server_url: Url, https: bool) { assert_eq!(http_gateway_details.domains, domains); assert_eq!(http_gateway_details.https_config, https_config); - // create a non-blocking reqwest client resolving localhost/example.com and .(raw.)localhost/example.com to 127.0.0.1 + // create a non-blocking reqwest client resolving localhost/example.com and .(raw.)localhost/example.com to [::1] let mut builder = NonblockingClient::builder(); for domain in [ localhost, @@ -302,7 +302,7 @@ async fn test_gateway(server_url: Url, https: bool) { ] { builder = builder.resolve( domain, - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port), + SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), port), ); } // add a custom root certificate @@ -345,13 +345,13 @@ async fn test_gateway(server_url: Url, https: bool) { .await .unwrap(); - // perform frontend asset request for the title page at http://127.0.0.1:/?canisterId= + // perform frontend asset request for the title page at http://[::1]:/?canisterId= let mut test_urls = vec![]; if !https { assert_eq!(proto, "http"); let canister_url = format!( "{}://{}:{}/?canisterId={}", - "http", "127.0.0.1", port, canister_id + "http", LOCALHOST, port, canister_id ); test_urls.push(canister_url); } @@ -1124,7 +1124,7 @@ fn test_gateway_ip_addr_host() { let mut endpoint = pic.make_live(None); endpoint - .set_ip_host(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))) + .set_ip_host(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))) .unwrap(); let rt = tokio::runtime::Builder::new_current_thread() @@ -1486,7 +1486,7 @@ fn test_gateway_address_in_use() { ) .unwrap_err(); assert!(err.contains(&format!( - "Failed to bind to address 127.0.0.1:{}: Address already in use", + "Failed to bind to address [::1]:{}: Address already in use", port ))); } From 5f080f1f0a1c249b5c6550a0134a7bd3ac5564db Mon Sep 17 00:00:00 2001 From: Martin Raszyk Date: Fri, 20 Dec 2024 13:51:14 +0100 Subject: [PATCH 2/2] .