From 0a0af0ecde8b0152e408f3a9340e7daab56626fb Mon Sep 17 00:00:00 2001
From: Niklas Adolfsson <niklasadolfsson1@gmail.com>
Date: Tue, 12 Nov 2024 18:07:21 +0100
Subject: [PATCH] rpc server: fix host filter for localhost on ipv6 (#6454)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This PR fixes an issue that I discovered using connecting to the RPC via
localhost using cURL, where cURL tries to connect to via ipv6 before
ipv4 when querying `localhost` which messed up the http host filter
whereas it would connect to the address `[::1]::9944 host_header:
localhost:9944` but the ipv6 interface only whitelisted `[::1]:9944`
which this fixes.

So let's whitelist all localhost interfaces to avoid such weird
edge-cases.

### Behavior before this PR

```bash
$ polkadot --chain westend-dev &
$ curl -v \
     -H 'Content-Type: application/json' \
     -d '{"jsonrpc":"2.0","id":"id","method":"system_name"}' \
     http://localhost:9944
* Host localhost:9944 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:9944...
* Connected to localhost (::1) port 9944
> POST / HTTP/1.1
> Host: localhost:9944
> User-Agent: curl/8.5.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 50
>
< HTTP/1.1 403 Forbidden
< content-type: text/plain
< content-length: 41
< date: Tue, 12 Nov 2024 13:03:49 GMT
<
Provided Host header is not whitelisted.
* Connection #0 to host localhost left intact
```

### Behavior after this PR
```bash
$ polkadot --chain westend-dev &
➜ wasm-tests (update-artifacts-1731284930) ✗ curl -v \
     -H 'Content-Type: application/json' \
     -d '{"jsonrpc":"2.0","id":"id","method":"system_name"}' \
     http://localhost:9944
* Host localhost:9944 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:9944...
* Connected to localhost (::1) port 9944
> POST / HTTP/1.1
> Host: localhost:9944
> User-Agent: curl/8.5.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 50
>
< HTTP/1.1 200 OK
< content-type: application/json; charset=utf-8
< vary: origin, access-control-request-method, access-control-request-headers
< content-length: 54
< date: Tue, 12 Nov 2024 13:02:57 GMT
<
* Connection #0 to host localhost left intact
{"jsonrpc":"2.0","id":"id","result":"Parity Polkadot"}%
```

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: command-bot <>
---
 prdoc/pr_6454.prdoc                       |  7 +++++++
 substrate/client/rpc-servers/src/utils.rs | 13 +++++--------
 2 files changed, 12 insertions(+), 8 deletions(-)
 create mode 100644 prdoc/pr_6454.prdoc

diff --git a/prdoc/pr_6454.prdoc b/prdoc/pr_6454.prdoc
new file mode 100644
index 00000000000..3fd3e39db60
--- /dev/null
+++ b/prdoc/pr_6454.prdoc
@@ -0,0 +1,7 @@
+title: 'rpc server: fix ipv6 host filter for localhost'
+doc:
+- audience: Node Operator
+  description: "This PR fixes that ipv6 connections to localhost was faulty rejected by the host filter because only [::1] was allowed"
+crates:
+- name: sc-rpc-server
+  bump: minor
diff --git a/substrate/client/rpc-servers/src/utils.rs b/substrate/client/rpc-servers/src/utils.rs
index d9b2db7af13..51cce622429 100644
--- a/substrate/client/rpc-servers/src/utils.rs
+++ b/substrate/client/rpc-servers/src/utils.rs
@@ -193,14 +193,11 @@ pub(crate) fn host_filtering(enabled: bool, addr: SocketAddr) -> Option<HostFilt
 	if enabled {
 		// NOTE: The listening addresses are whitelisted by default.
 
-		let mut hosts = Vec::new();
-
-		if addr.is_ipv4() {
-			hosts.push(format!("localhost:{}", addr.port()));
-			hosts.push(format!("127.0.0.1:{}", addr.port()));
-		} else {
-			hosts.push(format!("[::1]:{}", addr.port()));
-		}
+		let hosts = [
+			format!("localhost:{}", addr.port()),
+			format!("127.0.0.1:{}", addr.port()),
+			format!("[::1]:{}", addr.port()),
+		];
 
 		Some(HostFilterLayer::new(hosts).expect("Valid hosts; qed"))
 	} else {
-- 
GitLab