mirror of
https://github.com/Av0idD4rk/firegex.git
synced 2026-10-23 16:31:00 +00:00
Fix the ALLOWED_IPS allow-case check for containerised runs
IPFilterMiddleware matches the raw TCP peer address, which is 127.0.0.1 only when firegex shares the host's network namespace. Behind a published docker port the peer is the bridge gateway instead, so the scenario allowing 127.0.0.1/32,::1/128 got a 403 and the suite failed everywhere except standalone mode. Allow loopback plus the private ranges a docker bridge can occupy. The check keeps its meaning: the deny scenario uses 203.0.113.0/24 (TEST-NET-3), which no real peer can fall into, so the allow/deny pair still exercises the middleware.
This commit is contained in:
parent
eba2c9063a
commit
cb270b45ef
@ -115,6 +115,16 @@ def check_startup_password_survives_disabled_auth():
|
|||||||
got == "testpassword", f"got {got!r}")
|
got == "testpassword", f"got {got!r}")
|
||||||
|
|
||||||
|
|
||||||
|
# The middleware matches on the raw TCP peer address. That is 127.0.0.1 only when firegex
|
||||||
|
# shares the host's network namespace (standalone mode); behind a published docker port the
|
||||||
|
# peer is the bridge gateway instead - 172.17.0.1, 192.168.x.1, whatever the daemon picked.
|
||||||
|
# So "an allowlist that covers the client" has to name loopback *and* the private ranges a
|
||||||
|
# docker bridge can live in. That keeps the check meaningful: scenario 2 denies with
|
||||||
|
# 203.0.113.0/24 (TEST-NET-3, reserved for documentation), which no real peer can ever
|
||||||
|
# fall into, so the allow/deny pair still proves the middleware is doing its job.
|
||||||
|
CLIENT_NETWORKS = "127.0.0.1/32,::1/128,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,fc00::/7"
|
||||||
|
|
||||||
|
|
||||||
def raw_ws_handshake_rejected(path="/sock/socket.io/?EIO=4&transport=websocket", extra_headers=None, timeout=5):
|
def raw_ws_handshake_rejected(path="/sock/socket.io/?EIO=4&transport=websocket", extra_headers=None, timeout=5):
|
||||||
"""Best-effort check: performs a raw WS upgrade handshake and reports whether the
|
"""Best-effort check: performs a raw WS upgrade handshake and reports whether the
|
||||||
server completed it (101 Switching Protocols) or refused/closed the connection.
|
server completed it (101 Switching Protocols) or refused/closed the connection.
|
||||||
@ -161,8 +171,8 @@ if __name__ == "__main__":
|
|||||||
ws_rejected = raw_ws_handshake_rejected()
|
ws_rejected = raw_ws_handshake_rejected()
|
||||||
check("ALLOWED_IPS excludes client -> websocket upgrade rejected", ws_rejected is True, f"result={ws_rejected}")
|
check("ALLOWED_IPS excludes client -> websocket upgrade rejected", ws_rejected is True, f"result={ws_rejected}")
|
||||||
|
|
||||||
# 3. Restrict to a network (CIDR) that includes the loopback test client -> allowed
|
# 3. Restrict to networks (CIDR) that include the test client -> allowed
|
||||||
restart_with(allowed_ips="127.0.0.1/32,::1/128")
|
restart_with(allowed_ips=CLIENT_NETWORKS)
|
||||||
r = requests.get(BASE + "api/status")
|
r = requests.get(BASE + "api/status")
|
||||||
check("ALLOWED_IPS includes client (CIDR) -> 200", r.status_code == 200, f"got {r.status_code}")
|
check("ALLOWED_IPS includes client (CIDR) -> 200", r.status_code == 200, f"got {r.status_code}")
|
||||||
|
|
||||||
@ -172,7 +182,7 @@ if __name__ == "__main__":
|
|||||||
check("PROXY_IP_HEADER value matches allowlist -> 200", r.status_code == 200, f"got {r.status_code}")
|
check("PROXY_IP_HEADER value matches allowlist -> 200", r.status_code == 200, f"got {r.status_code}")
|
||||||
r = requests.get(BASE + "api/status", headers={"X-Forwarded-For": "8.8.8.8"})
|
r = requests.get(BASE + "api/status", headers={"X-Forwarded-For": "8.8.8.8"})
|
||||||
check("PROXY_IP_HEADER value NOT in allowlist -> 403", r.status_code == 403, f"got {r.status_code}")
|
check("PROXY_IP_HEADER value NOT in allowlist -> 403", r.status_code == 403, f"got {r.status_code}")
|
||||||
r = requests.get(BASE + "api/status") # header absent -> falls back to raw peer (127.0.0.1, not allowed here)
|
r = requests.get(BASE + "api/status") # header absent -> falls back to the raw peer, which 203.0.113.55/32 never covers
|
||||||
check("PROXY_IP_HEADER configured but header absent -> falls back to raw peer -> 403",
|
check("PROXY_IP_HEADER configured but header absent -> falls back to raw peer -> 403",
|
||||||
r.status_code == 403, f"got {r.status_code}")
|
r.status_code == 403, f"got {r.status_code}")
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user