From a61b0fcda858ea1ddce52bf87fccca55f1b7bb3f Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Thu, 19 Mar 2026 19:15:51 +0100 Subject: [PATCH] feat(haproxy): Add Sync WAF Routes button and fix LuCI backend routing - Add "Sync WAF Routes" button to HAProxy vhosts page in LuCI - Add sync_mitmproxy_routes RPC method to HAProxy RPCD backend - Fix mitmproxyctl and secubox-route to handle LuCI backends (luci, luci_default, luci_control) - Remove outdated port 8081 skip filter in route sync that prevented LuCI routes - These changes allow vhosts with original_backend='luci' to be properly routed through the WAF Co-Authored-By: Claude Opus 4.5 --- .claude/settings.local.json | 6 ++- .../luci-static/resources/haproxy/api.js | 9 +++++ .../resources/view/haproxy/vhosts.js | 22 ++++++++++- .../root/usr/libexec/rpcd/luci.haproxy | 32 +++++++++++++++- .../share/rpcd/acl.d/luci-app-haproxy.json | 3 +- .../files/usr/sbin/mitmproxyctl | 35 ++++++++++++----- .../secubox-core/root/usr/sbin/secubox-route | 38 +++++++++++-------- 7 files changed, 116 insertions(+), 29 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index d8b9111c..5000e778 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -596,7 +596,11 @@ "Bash(while read f)", "Bash(do basename \"$f\")", "Bash(git rebase:*)", - "Bash(GIT_EDITOR=true git rebase:*)" + "Bash(GIT_EDITOR=true git rebase:*)", + "Bash(gh release:*)", + "Bash(do gh run cancel $run)", + "Bash(while read id)", + "Bash(do echo \"=== $id ===\")" ] } } diff --git a/package/secubox/luci-app-haproxy/htdocs/luci-static/resources/haproxy/api.js b/package/secubox/luci-app-haproxy/htdocs/luci-static/resources/haproxy/api.js index 41bf543f..53aa5a41 100644 --- a/package/secubox/luci-app-haproxy/htdocs/luci-static/resources/haproxy/api.js +++ b/package/secubox/luci-app-haproxy/htdocs/luci-static/resources/haproxy/api.js @@ -288,6 +288,12 @@ var callListExposedServices = rpc.declare({ expect: { services: [] } }); +var callSyncMitmproxyRoutes = rpc.declare({ + object: 'luci.haproxy', + method: 'sync_mitmproxy_routes', + expect: {} +}); + // ============================================ // Helper Functions // ============================================ @@ -376,6 +382,9 @@ return baseclass.extend({ // Exposed services listExposedServices: callListExposedServices, + // Mitmproxy + syncMitmproxyRoutes: callSyncMitmproxyRoutes, + // Helpers getDashboardData: getDashboardData }); diff --git a/package/secubox/luci-app-haproxy/htdocs/luci-static/resources/view/haproxy/vhosts.js b/package/secubox/luci-app-haproxy/htdocs/luci-static/resources/view/haproxy/vhosts.js index f3e6fe50..fbc3a8fc 100644 --- a/package/secubox/luci-app-haproxy/htdocs/luci-static/resources/view/haproxy/vhosts.js +++ b/package/secubox/luci-app-haproxy/htdocs/luci-static/resources/view/haproxy/vhosts.js @@ -36,7 +36,12 @@ return view.extend({ ]), K.E('p', { 'style': 'margin: 4px 0 0; color: var(--kiss-muted, #94a3b8); font-size: 14px;' }, 'Configure domain-based routing to backend servers') - ]) + ]), + K.E('button', { + 'class': 'kiss-btn', + 'style': 'display: flex; align-items: center; gap: 6px;', + 'onClick': function() { self.handleSyncRoutes(); } + }, ['🔄 ', 'Sync WAF Routes']) ]), // Add Virtual Host Card @@ -271,6 +276,21 @@ return view.extend({ }); }, + handleSyncRoutes: function() { + var self = this; + self.showToast('Syncing mitmproxy routes...', 'info'); + + return api.syncMitmproxyRoutes().then(function(res) { + if (res.success) { + self.showToast('WAF routes synchronized successfully', 'success'); + } else { + self.showToast('Failed: ' + (res.error || 'Unknown error'), 'error'); + } + }).catch(function(err) { + self.showToast('Error: ' + err.message, 'error'); + }); + }, + handleToggleVhost: function(vh) { var self = this; var newEnabled = vh.enabled ? 0 : 1; diff --git a/package/secubox/luci-app-haproxy/root/usr/libexec/rpcd/luci.haproxy b/package/secubox/luci-app-haproxy/root/usr/libexec/rpcd/luci.haproxy index 81bc5ba5..ccf5fc24 100755 --- a/package/secubox/luci-app-haproxy/root/usr/libexec/rpcd/luci.haproxy +++ b/package/secubox/luci-app-haproxy/root/usr/libexec/rpcd/luci.haproxy @@ -1640,6 +1640,34 @@ _add_exposed_service() { json_close_object } +# Sync mitmproxy routes from HAProxy backends +method_sync_mitmproxy_routes() { + json_init + + # Run mitmproxyctl sync-routes + if command -v mitmproxyctl >/dev/null 2>&1; then + local output + output=$(mitmproxyctl sync-routes 2>&1) + local exit_code=$? + + if [ $exit_code -eq 0 ]; then + # Restart mitmproxy to apply new routes + /etc/init.d/mitmproxy restart >/dev/null 2>&1 + + json_add_boolean "success" 1 + json_add_string "message" "Routes synchronized and mitmproxy restarted" + else + json_add_boolean "success" 0 + json_add_string "error" "$output" + fi + else + json_add_boolean "success" 0 + json_add_string "error" "mitmproxyctl not found" + fi + + json_dump +} + # Main RPC interface case "$1" in list) @@ -1686,7 +1714,8 @@ case "$1" in "generate": {}, "validate": {}, "get_logs": { "lines": "integer" }, - "list_exposed_services": {} + "list_exposed_services": {}, + "sync_mitmproxy_routes": {} } EOF ;; @@ -1734,6 +1763,7 @@ EOF validate) method_validate ;; get_logs) method_get_logs ;; list_exposed_services) method_list_exposed_services ;; + sync_mitmproxy_routes) method_sync_mitmproxy_routes ;; esac ;; esac diff --git a/package/secubox/luci-app-haproxy/root/usr/share/rpcd/acl.d/luci-app-haproxy.json b/package/secubox/luci-app-haproxy/root/usr/share/rpcd/acl.d/luci-app-haproxy.json index a0c0fe42..5682a48f 100644 --- a/package/secubox/luci-app-haproxy/root/usr/share/rpcd/acl.d/luci-app-haproxy.json +++ b/package/secubox/luci-app-haproxy/root/usr/share/rpcd/acl.d/luci-app-haproxy.json @@ -54,7 +54,8 @@ "restart", "reload", "generate", - "validate" + "validate", + "sync_mitmproxy_routes" ] }, "uci": ["haproxy"] diff --git a/package/secubox/secubox-app-mitmproxy/files/usr/sbin/mitmproxyctl b/package/secubox/secubox-app-mitmproxy/files/usr/sbin/mitmproxyctl index 78ccdd8e..5f350d27 100755 --- a/package/secubox/secubox-app-mitmproxy/files/usr/sbin/mitmproxyctl +++ b/package/secubox/secubox-app-mitmproxy/files/usr/sbin/mitmproxyctl @@ -1665,24 +1665,39 @@ cmd_sync_routes_legacy() { backend=$(uci -q get haproxy.$vhost.original_backend) fi - # Skip fallback, luci, and mitmproxy backends + # Skip fallback and mitmproxy backends (no valid destination) case "$backend" in - fallback|luci|luci_default|mitmproxy_inspector|"") continue ;; + fallback|mitmproxy_inspector|"") continue ;; esac if [ -n "$domain" ] && [ -n "$backend" ]; then local ip="" local port="" + # Handle well-known backends with fixed addresses + case "$backend" in + luci|luci_default) + ip="127.0.0.1" + port="8081" + ;; + luci_control) + ip="192.168.255.1" + port="8515" + ;; + esac + # Method 1: Check for inline server field (old style) - local server=$(uci -q get haproxy.$backend.server) - if [ -n "$server" ]; then - # Parse server spec: "name ip:port check [options]" - local addr=$(echo "$server" | awk '{print $2}') - ip=$(echo "$addr" | cut -d':' -f1) - port=$(echo "$addr" | cut -d':' -f2) - # Handle backends without explicit port - [ "$ip" = "$port" ] && port="80" + # Only lookup if not already set by well-known backend + if [ -z "$ip" ]; then + local server=$(uci -q get haproxy.$backend.server) + if [ -n "$server" ]; then + # Parse server spec: "name ip:port check [options]" + local addr=$(echo "$server" | awk '{print $2}') + ip=$(echo "$addr" | cut -d':' -f1) + port=$(echo "$addr" | cut -d':' -f2) + # Handle backends without explicit port + [ "$ip" = "$port" ] && port="80" + fi fi # Method 2: Check for separate server section (new style) diff --git a/package/secubox/secubox-core/root/usr/sbin/secubox-route b/package/secubox/secubox-core/root/usr/sbin/secubox-route index a619919d..0c7ae673 100644 --- a/package/secubox/secubox-core/root/usr/sbin/secubox-route +++ b/package/secubox/secubox-core/root/usr/sbin/secubox-route @@ -196,12 +196,6 @@ cmd_sync() { [ -z "$domain" ] || [ -z "$host" ] || [ -z "$port" ] && continue - # Skip LuCI routes (port 8081) - if [ "$port" = "8081" ]; then - log_warn "Skipping LuCI route: $domain -> $host:8081" - continue - fi - if [ $first -eq 1 ]; then printf ' "%s": ["%s", %s]' "$domain" "$host" "$port" >> "$tmp_file" first=0 @@ -290,21 +284,35 @@ cmd_import_haproxy() { fi fi - # Skip special backends + # Skip backends without valid destinations case "$backend" in - fallback|luci|luci_default|mitmproxy_inspector|"") continue ;; + fallback|mitmproxy_inspector|"") continue ;; esac # Find backend server info local ip="" port="" - # Method 1: Check inline server field - local server=$(uci -q get haproxy.$backend.server) - if [ -n "$server" ]; then - local addr=$(echo "$server" | awk '{print $2}') - ip=$(echo "$addr" | cut -d':' -f1) - port=$(echo "$addr" | cut -d':' -f2) - [ "$ip" = "$port" ] && port="80" + # Handle well-known backends with fixed addresses + case "$backend" in + luci|luci_default) + ip="127.0.0.1" + port="8081" + ;; + luci_control) + ip="192.168.255.1" + port="8515" + ;; + esac + + # Method 1: Check inline server field (only if not already set) + if [ -z "$ip" ]; then + local server=$(uci -q get haproxy.$backend.server) + if [ -n "$server" ]; then + local addr=$(echo "$server" | awk '{print $2}') + ip=$(echo "$addr" | cut -d':' -f1) + port=$(echo "$addr" | cut -d':' -f2) + [ "$ip" = "$port" ] && port="80" + fi fi # Method 2: Check separate server section