mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-06-29 19:43:27 +00:00
Compare commits
2 Commits
8bb546c689
...
72b7eca12e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72b7eca12e | ||
| 0d1c49307e |
|
|
@ -712,6 +712,12 @@ class SecuBoxWAF:
|
|||
if ROUTES_FILE.exists():
|
||||
try:
|
||||
self.routes = json.loads(ROUTES_FILE.read_text())
|
||||
sfx = set()
|
||||
for _h in self.routes:
|
||||
_p = _h.split('.')
|
||||
if len(_p) >= 2 and not _p[-1].isdigit():
|
||||
sfx.add('.'.join(_p[-2:]))
|
||||
self.local_suffixes = sfx
|
||||
ctx.log.info(f"Loaded {len(self.routes)} routes")
|
||||
except Exception as e:
|
||||
ctx.log.error(f"Failed to load routes: {e}")
|
||||
|
|
@ -920,12 +926,12 @@ class SecuBoxWAF:
|
|||
ctx.log.warn(f"BAN FAILED for {ip} ({reason}) : LAPI off + cscli unavailable")
|
||||
|
||||
def requestheaders(self, flow: http.HTTPFlow):
|
||||
# #603 — mitmproxy 11 opens the upstream connection BETWEEN the
|
||||
# requestheaders and request hooks, so upstream redirection must
|
||||
# happen here. Doing it in request() (below) is too late: the
|
||||
# socket is already connected to the original Host, so routed
|
||||
# vhosts went to their public DNS IP instead of the internal
|
||||
# backend. Setting flow.server_conn.address here fixes routing.
|
||||
# #605 — mitmproxy 11 opens the upstream connection before request(),
|
||||
# so routing must happen here. ALSO: in --mode regular mitmproxy is a
|
||||
# forward proxy that would relay ANY Host, so internet scanners abused
|
||||
# it as an open proxy (~70% error churn + self-loops). Serve ONLY our
|
||||
# own vhosts: mapped (routes), our domains (-> nginx catch-all), or our
|
||||
# own IPs; refuse everything else with 421 and never open an upstream.
|
||||
try:
|
||||
host = flow.request.pretty_host
|
||||
if host in self.routes:
|
||||
|
|
@ -938,9 +944,32 @@ class SecuBoxWAF:
|
|||
except Exception:
|
||||
pass
|
||||
flow.request.headers['Host'] = orig
|
||||
return
|
||||
if host in SELF_HOSTS or self._is_local_host(host):
|
||||
flow.request.host = '192.168.1.200'
|
||||
flow.request.port = 9080
|
||||
try:
|
||||
flow.server_conn.address = ('192.168.1.200', 9080)
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
self.stats['blocked'] = self.stats.get('blocked', 0) + 1
|
||||
flow.response = http.Response.make(
|
||||
421,
|
||||
b'<h1>421 Misdirected Request</h1><p>SecuBox WAF does not proxy this host.</p>',
|
||||
{'Content-Type': 'text/html', 'X-SecuBox-WAF': 'unmapped-host'},
|
||||
)
|
||||
except Exception as e:
|
||||
ctx.log.warn(f'[requestheaders-route] {e}')
|
||||
|
||||
def _is_local_host(self, host: str) -> bool:
|
||||
# #605 — is `host` one of our own (registrable) domains? Derived from
|
||||
# the routed hosts in load_routes (self.local_suffixes).
|
||||
sfx = getattr(self, 'local_suffixes', None)
|
||||
if not sfx:
|
||||
return False
|
||||
return any(host == s or host.endswith('.' + s) for s in sfx)
|
||||
|
||||
def request(self, flow: http.HTTPFlow):
|
||||
# Connection close (Phase 6.J leak fix, ref #496) — prevents mitmproxy
|
||||
# from accumulating idle keep-alive sockets to upstream backends.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,15 @@
|
|||
secubox-mitmproxy (1.0.6-1~bookworm1) bookworm; urgency=medium
|
||||
|
||||
* fix(waf): refuse unmapped hosts — close the open forward-proxy (#605). In
|
||||
--mode regular the addon relayed any Host, so HAProxy's default_backend
|
||||
made the WAF an open proxy; internet scanners drove ~72% backend-error
|
||||
churn + self-loops. The `requestheaders` hook now serves ONLY our vhosts
|
||||
(mapped, our domains via routes-derived `local_suffixes` → nginx catch-all,
|
||||
or our own IPs) and returns 421 for everything else with no upstream
|
||||
connect. Verified live: 0 external server-connects, 0 loop-508s.
|
||||
|
||||
-- Gerald KERMA <devel@cybermind.fr> Mon, 15 Jun 2026 16:30:00 +0200
|
||||
|
||||
secubox-mitmproxy (1.0.5-1~bookworm1) bookworm; urgency=medium
|
||||
|
||||
* fix(waf): mitmproxy-11 upstream routing (#603). The addon only redirected
|
||||
|
|
|
|||
|
|
@ -1,3 +1,12 @@
|
|||
secubox-waf (1.2.4-1~bookworm1) bookworm; urgency=medium
|
||||
|
||||
* fix(waf): refuse unmapped hosts in the addon copy — close the open
|
||||
forward-proxy (#605, synced with secubox-mitmproxy). 421 for any host not
|
||||
in routes / our domains / our IPs; no upstream connect. Kills the ~72%
|
||||
scanner-driven error churn and the self-loop 508s.
|
||||
|
||||
-- Gerald KERMA <devel@cybermind.fr> Mon, 15 Jun 2026 16:30:00 +0200
|
||||
|
||||
secubox-waf (1.2.3-1~bookworm1) bookworm; urgency=medium
|
||||
|
||||
* fix(waf): mitmproxy-11 upstream routing — `requestheaders` hook in the
|
||||
|
|
|
|||
|
|
@ -594,6 +594,12 @@ class SecuBoxWAF:
|
|||
if ROUTES_FILE.exists():
|
||||
try:
|
||||
self.routes = json.loads(ROUTES_FILE.read_text())
|
||||
sfx = set()
|
||||
for _h in self.routes:
|
||||
_p = _h.split('.')
|
||||
if len(_p) >= 2 and not _p[-1].isdigit():
|
||||
sfx.add('.'.join(_p[-2:]))
|
||||
self.local_suffixes = sfx
|
||||
ctx.log.info(f"Loaded {len(self.routes)} routes")
|
||||
except Exception as e:
|
||||
ctx.log.error(f"Failed to load routes: {e}")
|
||||
|
|
@ -776,12 +782,12 @@ class SecuBoxWAF:
|
|||
ctx.log.warn(f"BAN FAILED for {ip} ({reason})")
|
||||
|
||||
def requestheaders(self, flow: http.HTTPFlow):
|
||||
# #603 — mitmproxy 11 opens the upstream connection BETWEEN the
|
||||
# requestheaders and request hooks, so upstream redirection must
|
||||
# happen here. Doing it in request() (below) is too late: the
|
||||
# socket is already connected to the original Host, so routed
|
||||
# vhosts went to their public DNS IP instead of the internal
|
||||
# backend. Setting flow.server_conn.address here fixes routing.
|
||||
# #605 — mitmproxy 11 opens the upstream connection before request(),
|
||||
# so routing must happen here. ALSO: in --mode regular mitmproxy is a
|
||||
# forward proxy that would relay ANY Host, so internet scanners abused
|
||||
# it as an open proxy (~70% error churn + self-loops). Serve ONLY our
|
||||
# own vhosts: mapped (routes), our domains (-> nginx catch-all), or our
|
||||
# own IPs; refuse everything else with 421 and never open an upstream.
|
||||
try:
|
||||
host = flow.request.pretty_host
|
||||
if host in self.routes:
|
||||
|
|
@ -794,9 +800,32 @@ class SecuBoxWAF:
|
|||
except Exception:
|
||||
pass
|
||||
flow.request.headers['Host'] = orig
|
||||
return
|
||||
if host in SELF_HOSTS or self._is_local_host(host):
|
||||
flow.request.host = '192.168.1.200'
|
||||
flow.request.port = 9080
|
||||
try:
|
||||
flow.server_conn.address = ('192.168.1.200', 9080)
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
self.stats['blocked'] = self.stats.get('blocked', 0) + 1
|
||||
flow.response = http.Response.make(
|
||||
421,
|
||||
b'<h1>421 Misdirected Request</h1><p>SecuBox WAF does not proxy this host.</p>',
|
||||
{'Content-Type': 'text/html', 'X-SecuBox-WAF': 'unmapped-host'},
|
||||
)
|
||||
except Exception as e:
|
||||
ctx.log.warn(f'[requestheaders-route] {e}')
|
||||
|
||||
def _is_local_host(self, host: str) -> bool:
|
||||
# #605 — is `host` one of our own (registrable) domains? Derived from
|
||||
# the routed hosts in load_routes (self.local_suffixes).
|
||||
sfx = getattr(self, 'local_suffixes', None)
|
||||
if not sfx:
|
||||
return False
|
||||
return any(host == s or host.endswith('.' + s) for s in sfx)
|
||||
|
||||
def request(self, flow: http.HTTPFlow):
|
||||
# Connection close (Phase 6.J leak fix, ref #496) — prevents mitmproxy
|
||||
# from accumulating idle keep-alive sockets to upstream backends.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user