secubox-openwrt/package/secubox/luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy
CyberMind-FR f8c20a6c87 fix: Use pgrep -x for exact process matching in mitmproxy RPCD
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 15:30:16 +01:00

308 lines
7.4 KiB
Bash
Executable File

#!/bin/sh
#
# RPCD backend for mitmproxy LuCI interface
# Copyright (C) 2025 CyberMind.fr (SecuBox)
#
. /lib/functions.sh
CONF_DIR=/etc/mitmproxy
DATA_DIR=/tmp/mitmproxy
LOG_FILE=/tmp/mitmproxy/requests.log
FLOW_FILE=/tmp/mitmproxy/flows.bin
# JSON helpers
json_init() { echo "{"; }
json_close() { echo "}"; }
json_add_string() { printf '"%s":"%s"' "$1" "$2"; }
json_add_int() { printf '"%s":%d' "$1" "${2:-0}"; }
json_add_bool() { [ "$2" = "1" ] && printf '"%s":true' "$1" || printf '"%s":false' "$1"; }
# Get service status
get_status() {
local running=0
local pid=""
local mode="unknown"
local web_url=""
if pgrep -x mitmweb >/dev/null 2>&1; then
running=1
pid=$(pgrep -x mitmweb | head -1)
mode="mitmweb"
elif pgrep -x mitmdump >/dev/null 2>&1; then
running=1
pid=$(pgrep -x mitmdump | head -1)
mode="mitmdump"
elif pgrep -f "python.*mitmproxy" >/dev/null 2>&1; then
running=1
pid=$(pgrep -f "python.*mitmproxy" | head -1)
mode="mitmproxy"
fi
local enabled=$(uci -q get mitmproxy.main.enabled || echo "0")
local listen_port=$(uci -q get mitmproxy.main.listen_port || echo "8080")
local web_port=$(uci -q get mitmproxy.main.web_port || echo "8081")
local proxy_mode=$(uci -q get mitmproxy.main.mode || echo "transparent")
local router_ip=$(uci -q get network.lan.ipaddr || echo "192.168.1.1")
[ "$running" = "1" ] && [ "$mode" = "mitmweb" ] && web_url="http://${router_ip}:${web_port}"
cat <<EOF
{
"running": $([ "$running" = "1" ] && echo "true" || echo "false"),
"enabled": $([ "$enabled" = "1" ] && echo "true" || echo "false"),
"pid": ${pid:-0},
"mode": "$mode",
"proxy_mode": "$proxy_mode",
"listen_port": $listen_port,
"web_port": $web_port,
"web_url": "$web_url",
"ca_installed": $([ -f "$CONF_DIR/mitmproxy-ca-cert.pem" ] && echo "true" || echo "false")
}
EOF
}
# Get configuration
get_config() {
local enabled=$(uci -q get mitmproxy.main.enabled || echo "0")
local mode=$(uci -q get mitmproxy.main.mode || echo "transparent")
local listen_host=$(uci -q get mitmproxy.main.listen_host || echo "0.0.0.0")
local listen_port=$(uci -q get mitmproxy.main.listen_port || echo "8080")
local web_host=$(uci -q get mitmproxy.main.web_host || echo "0.0.0.0")
local web_port=$(uci -q get mitmproxy.main.web_port || echo "8081")
local ssl_insecure=$(uci -q get mitmproxy.main.ssl_insecure || echo "0")
local flow_detail=$(uci -q get mitmproxy.main.flow_detail || echo "2")
local save_flows=$(uci -q get mitmproxy.capture.save_flows || echo "1")
local capture_urls=$(uci -q get mitmproxy.capture.capture_urls || echo "1")
local capture_cookies=$(uci -q get mitmproxy.capture.capture_cookies || echo "1")
local capture_headers=$(uci -q get mitmproxy.capture.capture_headers || echo "1")
local capture_body=$(uci -q get mitmproxy.capture.capture_body || echo "0")
cat <<EOF
{
"enabled": $([ "$enabled" = "1" ] && echo "true" || echo "false"),
"mode": "$mode",
"listen_host": "$listen_host",
"listen_port": $listen_port,
"web_host": "$web_host",
"web_port": $web_port,
"ssl_insecure": $([ "$ssl_insecure" = "1" ] && echo "true" || echo "false"),
"flow_detail": $flow_detail,
"save_flows": $([ "$save_flows" = "1" ] && echo "true" || echo "false"),
"capture_urls": $([ "$capture_urls" = "1" ] && echo "true" || echo "false"),
"capture_cookies": $([ "$capture_cookies" = "1" ] && echo "true" || echo "false"),
"capture_headers": $([ "$capture_headers" = "1" ] && echo "true" || echo "false"),
"capture_body": $([ "$capture_body" = "1" ] && echo "true" || echo "false")
}
EOF
}
# Get statistics
get_stats() {
local total_requests=0
local unique_hosts=0
local flow_size="0"
if [ -f "$LOG_FILE" ]; then
total_requests=$(wc -l < "$LOG_FILE" 2>/dev/null || echo "0")
if command -v jq >/dev/null 2>&1; then
unique_hosts=$(jq -r '.request.host // .host // empty' "$LOG_FILE" 2>/dev/null | sort -u | wc -l)
fi
fi
if [ -f "$FLOW_FILE" ]; then
flow_size=$(ls -l "$FLOW_FILE" 2>/dev/null | awk '{print $5}' || echo "0")
fi
cat <<EOF
{
"total_requests": $total_requests,
"unique_hosts": $unique_hosts,
"flow_file_size": $flow_size
}
EOF
}
# Get recent requests
get_requests() {
local limit="${1:-50}"
if [ ! -f "$LOG_FILE" ]; then
echo '{"requests":[]}'
return
fi
if command -v jq >/dev/null 2>&1; then
echo '{"requests":'
tail -"$limit" "$LOG_FILE" 2>/dev/null | jq -s '.' 2>/dev/null || echo '[]'
echo '}'
else
echo '{"requests":[]}'
fi
}
# Get top hosts
get_top_hosts() {
local limit="${1:-20}"
if [ ! -f "$LOG_FILE" ] || ! command -v jq >/dev/null 2>&1; then
echo '{"hosts":[]}'
return
fi
echo '{"hosts":['
jq -r '.request.host // .host // "unknown"' "$LOG_FILE" 2>/dev/null | \
sort | uniq -c | sort -rn | head -"$limit" | \
awk 'BEGIN{first=1} {
if(!first) printf ",";
first=0;
gsub(/"/, "\\\"", $2);
printf "{\"host\":\"%s\",\"count\":%d}", $2, $1
}'
echo ']}'
}
# Service control
service_start() {
/etc/init.d/mitmproxy start >/dev/null 2>&1
sleep 2
get_status
}
service_stop() {
/etc/init.d/mitmproxy stop >/dev/null 2>&1
sleep 1
get_status
}
service_restart() {
/etc/init.d/mitmproxy restart >/dev/null 2>&1
sleep 2
get_status
}
# Set configuration
set_config() {
local key="$1"
local value="$2"
local section="main"
case "$key" in
save_flows|capture_*)
section="capture"
;;
esac
uci set "mitmproxy.$section.$key=$value"
uci commit mitmproxy
echo '{"success":true}'
}
# Clear captured data
clear_data() {
rm -f "$DATA_DIR"/*.log "$DATA_DIR"/*.bin 2>/dev/null
echo '{"success":true,"message":"Captured data cleared"}'
}
# Get CA certificate info
get_ca_info() {
local cert="$CONF_DIR/mitmproxy-ca-cert.pem"
local router_ip=$(uci -q get network.lan.ipaddr || echo "192.168.1.1")
local web_port=$(uci -q get mitmproxy.main.web_port || echo "8081")
if [ -f "$cert" ]; then
local subject=$(openssl x509 -in "$cert" -noout -subject 2>/dev/null | sed 's/subject=//')
local expires=$(openssl x509 -in "$cert" -noout -enddate 2>/dev/null | sed 's/notAfter=//')
cat <<EOF
{
"installed": true,
"path": "$cert",
"subject": "$subject",
"expires": "$expires",
"download_url": "http://$router_ip:$web_port/cert"
}
EOF
else
cat <<EOF
{
"installed": false,
"path": "$cert",
"download_url": ""
}
EOF
fi
}
# RPCD list method
case "$1" in
list)
cat <<EOF
{
"get_status": {},
"get_config": {},
"get_stats": {},
"get_requests": {"limit": 50},
"get_top_hosts": {"limit": 20},
"get_ca_info": {},
"service_start": {},
"service_stop": {},
"service_restart": {},
"set_config": {"key": "string", "value": "string"},
"clear_data": {}
}
EOF
;;
call)
case "$2" in
get_status)
get_status
;;
get_config)
get_config
;;
get_stats)
get_stats
;;
get_requests)
read -r input
limit=$(echo "$input" | jsonfilter -e '@.limit' 2>/dev/null || echo "50")
get_requests "$limit"
;;
get_top_hosts)
read -r input
limit=$(echo "$input" | jsonfilter -e '@.limit' 2>/dev/null || echo "20")
get_top_hosts "$limit"
;;
get_ca_info)
get_ca_info
;;
service_start)
service_start
;;
service_stop)
service_stop
;;
service_restart)
service_restart
;;
set_config)
read -r input
key=$(echo "$input" | jsonfilter -e '@.key' 2>/dev/null)
value=$(echo "$input" | jsonfilter -e '@.value' 2>/dev/null)
set_config "$key" "$value"
;;
clear_data)
clear_data
;;
*)
echo '{"error":"Unknown method"}'
;;
esac
;;
*)
echo '{"error":"Unknown command"}'
;;
esac