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 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-03-19 19:15:51 +01:00
parent 64a12a65ad
commit a61b0fcda8
7 changed files with 116 additions and 29 deletions

View File

@ -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 ===\")"
]
}
}

View File

@ -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
});

View File

@ -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;

View File

@ -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

View File

@ -54,7 +54,8 @@
"restart",
"reload",
"generate",
"validate"
"validate",
"sync_mitmproxy_routes"
]
},
"uci": ["haproxy"]

View File

@ -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)

View File

@ -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