feat(secubox-app-mitmproxy): Add LXC container support for mitmproxy

- Create mitmproxyctl script with LXC container management
- Alpine Linux rootfs with Python and mitmproxy via pip
- Support for regular, transparent, upstream, and reverse proxy modes
- UCI configuration for proxy_port, web_port, memory_limit, etc.
- procd init script for service management
- Update luci-app-mitmproxy RPCD backend for LXC container status

Ports:
- 8080: Proxy port
- 8081: Web interface (mitmweb)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-01-17 06:40:08 +01:00
parent c02c3d2a3a
commit c99d49739e
5 changed files with 542 additions and 475 deletions

View File

@ -6,10 +6,11 @@
. /lib/functions.sh
CONF_DIR=/etc/mitmproxy
DATA_DIR=/tmp/mitmproxy
LOG_FILE=/tmp/mitmproxy/requests.log
FLOW_FILE=/tmp/mitmproxy/flows.bin
DATA_DIR=$(uci -q get mitmproxy.main.data_path || echo "/srv/mitmproxy")
LXC_NAME="mitmproxy"
CONF_DIR="$DATA_DIR"
LOG_FILE="$DATA_DIR/requests.log"
FLOW_FILE="$DATA_DIR/flows.bin"
# JSON helpers
json_init() { echo "{"; }
@ -24,25 +25,35 @@ get_status() {
local pid=""
local mode="unknown"
local web_url=""
local lxc_state=""
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"
# Check LXC container status
if command -v lxc-info >/dev/null 2>&1; then
lxc_state=$(lxc-info -n "$LXC_NAME" -s 2>/dev/null | grep -oE 'RUNNING|STOPPED' || echo "UNKNOWN")
if [ "$lxc_state" = "RUNNING" ]; then
running=1
mode="mitmweb"
pid=$(lxc-info -n "$LXC_NAME" -p 2>/dev/null | grep -oE '[0-9]+' || echo "0")
fi
fi
# Fallback: check for direct process
if [ "$running" = "0" ]; then
if pgrep mitmweb >/dev/null 2>&1; then
running=1
pid=$(pgrep mitmweb | head -1)
mode="mitmweb"
elif pgrep mitmdump >/dev/null 2>&1; then
running=1
pid=$(pgrep mitmdump | head -1)
mode="mitmdump"
fi
fi
local enabled=$(uci -q get mitmproxy.main.enabled || echo "0")
local listen_port=$(uci -q get mitmproxy.main.listen_port || echo "8080")
local proxy_port=$(uci -q get mitmproxy.main.proxy_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 proxy_mode=$(uci -q get mitmproxy.main.mode || echo "regular")
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}"
@ -54,7 +65,8 @@ get_status() {
"pid": ${pid:-0},
"mode": "$mode",
"proxy_mode": "$proxy_mode",
"listen_port": $listen_port,
"lxc_state": "$lxc_state",
"proxy_port": $proxy_port,
"web_port": $web_port,
"web_url": "$web_url",
"ca_installed": $([ -f "$CONF_DIR/mitmproxy-ca-cert.pem" ] && echo "true" || echo "false")
@ -65,35 +77,30 @@ 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 mode=$(uci -q get mitmproxy.main.mode || echo "regular")
local proxy_port=$(uci -q get mitmproxy.main.proxy_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 data_path=$(uci -q get mitmproxy.main.data_path || echo "/srv/mitmproxy")
local memory_limit=$(uci -q get mitmproxy.main.memory_limit || echo "256M")
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")
local anticache=$(uci -q get mitmproxy.main.anticache || echo "0")
local anticomp=$(uci -q get mitmproxy.main.anticomp || echo "0")
local flow_detail=$(uci -q get mitmproxy.main.flow_detail || echo "1")
cat <<EOF
{
"enabled": $([ "$enabled" = "1" ] && echo "true" || echo "false"),
"mode": "$mode",
"listen_host": "$listen_host",
"listen_port": $listen_port,
"proxy_port": $proxy_port,
"web_host": "$web_host",
"web_port": $web_port,
"data_path": "$data_path",
"memory_limit": "$memory_limit",
"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")
"anticache": $([ "$anticache" = "1" ] && echo "true" || echo "false"),
"anticomp": $([ "$anticomp" = "1" ] && echo "true" || echo "false"),
"flow_detail": $flow_detail
}
EOF
}

View File

@ -1,47 +1,34 @@
#
# Copyright (C) 2025 CyberMind.fr (SecuBox)
#
# This is free software, licensed under the MIT License.
#
# secubox-app-mitmproxy - mitmproxy integration for SecuBox
# Provides init scripts, UCI configuration, and control utilities
# mitmproxy binary must be installed separately via pip
#
include $(TOPDIR)/rules.mk
PKG_NAME:=secubox-app-mitmproxy
PKG_VERSION:=2.2.0
PKG_RELEASE:=1
PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
PKG_LICENSE:=MIT
PKG_VERSION:=1.0.0
PKG_ARCH:=all
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>
PKG_LICENSE:=Apache-2.0
include $(INCLUDE_DIR)/package.mk
define Package/secubox-app-mitmproxy
SECTION:=net
CATEGORY:=Network
SUBMENU:=SecuBox Apps
TITLE:=mitmproxy - Interactive HTTPS Proxy (SecuBox Integration)
URL:=https://mitmproxy.org/
DEPENDS:=+python3 +jq +openssl-util
SECTION:=utils
CATEGORY:=Utilities
PKGARCH:=all
SUBMENU:=SecuBox Apps
TITLE:=SecuBox mitmproxy HTTPS Intercepting Proxy (LXC)
DEPENDS:=+uci +libuci +wget +tar
endef
define Package/secubox-app-mitmproxy/description
SecuBox integration package for mitmproxy.
Provides init scripts, UCI configuration, and control utilities.
mitmproxy - Interactive HTTPS proxy for SecuBox-powered OpenWrt systems.
NOTE: mitmproxy binary must be installed separately via pip:
pip3 install mitmproxy
Features:
- Intercept and inspect HTTP/HTTPS traffic
- Modify requests and responses on the fly
- Web interface (mitmweb) for easy analysis
- Export traffic for offline analysis
Features:
- Intercept and modify HTTP/HTTPS traffic
- Web-based interface (mitmweb)
- Scripting API for automation
- SSL/TLS certificate generation
- Transparent proxy mode with iptables
Runs in LXC container for isolation and security.
Configure in /etc/config/mitmproxy.
endef
define Package/secubox-app-mitmproxy/conffiles
@ -52,62 +39,33 @@ define Build/Compile
endef
define Package/secubox-app-mitmproxy/install
# Wrapper scripts
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) ./files/usr/bin/mitmproxy $(1)/usr/bin/mitmproxy
$(INSTALL_BIN) ./files/usr/bin/mitmdump $(1)/usr/bin/mitmdump
$(INSTALL_BIN) ./files/usr/bin/mitmweb $(1)/usr/bin/mitmweb
# Config
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./files/etc/config/mitmproxy $(1)/etc/config/mitmproxy
# Init script
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/etc/init.d/mitmproxy $(1)/etc/init.d/mitmproxy
# Controller script
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) ./files/usr/sbin/mitmproxyctl $(1)/usr/sbin/mitmproxyctl
# CA certificate directory
$(INSTALL_DIR) $(1)/etc/mitmproxy
endef
define Package/secubox-app-mitmproxy/postinst
#!/bin/sh
[ -n "$${IPKG_INSTROOT}" ] || {
# Create runtime directories
mkdir -p /var/lib/mitmproxy /tmp/mitmproxy /etc/mitmproxy
# Check if mitmproxy is installed
if python3 -c "import mitmproxy" 2>/dev/null; then
echo "mitmproxy detected"
# Generate CA certificate if needed
if [ ! -f /etc/mitmproxy/mitmproxy-ca.pem ]; then
echo "Generating mitmproxy CA certificate..."
/usr/bin/mitmdump --set confdir=/etc/mitmproxy -q &
sleep 5
killall mitmdump 2>/dev/null || killall python3 2>/dev/null || true
fi
/etc/init.d/mitmproxy enable
echo "mitmproxy service enabled. Start with: /etc/init.d/mitmproxy start"
else
echo "NOTE: mitmproxy binary not found."
echo "Install via pip: pip3 install mitmproxy"
echo "Then enable service: /etc/init.d/mitmproxy enable"
fi
}
exit 0
endef
define Package/secubox-app-mitmproxy/prerm
#!/bin/sh
[ -n "$${IPKG_INSTROOT}" ] || {
/etc/init.d/mitmproxy stop
/etc/init.d/mitmproxy disable
echo ""
echo "mitmproxy installed."
echo ""
echo "To install and start mitmproxy:"
echo " mitmproxyctl install"
echo " /etc/init.d/mitmproxy start"
echo ""
echo "Web interface: http://<router-ip>:8081"
echo "Proxy port: 8080"
echo ""
echo "To use the proxy, configure clients with:"
echo " HTTP Proxy: <router-ip>:8080"
echo " Install CA cert from: http://<router-ip>:8081/cert"
echo ""
}
exit 0
endef

View File

@ -1,32 +1,16 @@
config mitmproxy 'main'
option enabled '0'
option mode 'transparent'
option listen_host '0.0.0.0'
option listen_port '8080'
option runtime 'lxc'
option proxy_port '8080'
option web_port '8081'
option web_host '0.0.0.0'
option confdir '/etc/mitmproxy'
option data_path '/srv/mitmproxy'
option memory_limit '256M'
option mode 'regular'
# mode: regular, transparent, upstream, reverse
# option upstream_proxy 'http://proxy:8080'
# option reverse_target 'http://localhost:80'
option ssl_insecure '0'
option showhost '1'
option flow_detail '2'
config logging 'logging'
option enabled '1'
option log_file '/tmp/mitmproxy/requests.log'
option log_format 'json'
option max_size '10'
config capture 'capture'
option save_flows '1'
option flow_file '/tmp/mitmproxy/flows.bin'
option capture_urls '1'
option capture_cookies '1'
option capture_headers '1'
option capture_body '0'
config filter 'filter'
option enabled '0'
option block_ads '0'
option block_trackers '0'
list ignore_host 'localhost'
list ignore_host '*.local'
option anticache '0'
option anticomp '0'
option flow_detail '1'

View File

@ -1,131 +1,33 @@
#!/bin/sh /etc/rc.common
#
# mitmproxy init script for OpenWrt
# Copyright (C) 2025 CyberMind.fr (SecuBox)
#
START=95
STOP=10
USE_PROCD=1
PROG=/usr/bin/mitmweb
CONF_DIR=/etc/mitmproxy
PID_FILE=/var/run/mitmproxy.pid
PROG=/usr/sbin/mitmproxyctl
NAME=mitmproxy
CONFIG=mitmproxy
validate_section() {
uci_load_validate mitmproxy main "$1" "$2" \
'enabled:bool:0' \
'mode:string:transparent' \
'listen_host:string:0.0.0.0' \
'listen_port:port:8080' \
'web_port:port:8081' \
'web_host:string:0.0.0.0' \
'confdir:string:/etc/mitmproxy' \
'ssl_insecure:bool:0' \
'showhost:bool:1' \
'flow_detail:range(0,4):2'
}
start_mitmproxy() {
[ "$2" = 0 ] || {
echo "mitmproxy: validation failed" >&2
return 1
}
start_service() {
local enabled
config_load "$CONFIG"
config_get enabled main enabled '0'
[ "$enabled" = "1" ] || {
echo "mitmproxy: disabled in config"
echo "mitmproxy is disabled. Enable with: uci set mitmproxy.main.enabled=1"
return 0
}
# Create directories
mkdir -p /tmp/mitmproxy
mkdir -p /var/lib/mitmproxy
procd_open_instance mitmproxy
procd_set_param command $PROG
# Core options
procd_append_param command --set confdir="$confdir"
procd_append_param command --listen-host "$listen_host"
procd_append_param command --listen-port "$listen_port"
procd_append_param command --web-host "$web_host"
procd_append_param command --web-port "$web_port"
procd_append_param command --set flow_detail="$flow_detail"
# Mode
case "$mode" in
transparent)
procd_append_param command --mode transparent
;;
regular)
procd_append_param command --mode regular
;;
upstream)
procd_append_param command --mode upstream
;;
esac
# SSL options
[ "$ssl_insecure" = "1" ] && procd_append_param command --ssl-insecure
[ "$showhost" = "1" ] && procd_append_param command --showhost
# Capture options
local save_flows flow_file
config_get save_flows capture save_flows 0
config_get flow_file capture flow_file "/tmp/mitmproxy/flows.bin"
[ "$save_flows" = "1" ] && procd_append_param command -w "$flow_file"
procd_set_param respawn
procd_open_instance
procd_set_param command "$PROG" service-run
procd_set_param respawn 3600 5 5
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param pidfile $PID_FILE
procd_close_instance
# Setup iptables rules for transparent mode
[ "$mode" = "transparent" ] && setup_iptables "$listen_port"
}
setup_iptables() {
local port="$1"
# Remove existing rules first
cleanup_iptables
# Get LAN interface
local lan_ip=$(uci -q get network.lan.ipaddr || echo "192.168.1.1")
# Redirect HTTP traffic
iptables -t nat -A PREROUTING -i br-lan -p tcp --dport 80 \
-j REDIRECT --to-port "$port" 2>/dev/null
# Redirect HTTPS traffic
iptables -t nat -A PREROUTING -i br-lan -p tcp --dport 443 \
-j REDIRECT --to-port "$port" 2>/dev/null
# Mark mitmproxy traffic
iptables -t nat -I PREROUTING -p tcp -m mark --mark 0x1/0x1 -j ACCEPT 2>/dev/null
}
cleanup_iptables() {
# Get configured port (default 8080)
local port=$(uci -q get mitmproxy.main.listen_port || echo "8080")
# Remove mitmproxy redirect rules
iptables -t nat -D PREROUTING -i br-lan -p tcp --dport 80 \
-j REDIRECT --to-port "$port" 2>/dev/null
iptables -t nat -D PREROUTING -i br-lan -p tcp --dport 443 \
-j REDIRECT --to-port "$port" 2>/dev/null
iptables -t nat -D PREROUTING -p tcp -m mark --mark 0x1/0x1 -j ACCEPT 2>/dev/null
}
start_service() {
config_load mitmproxy
config_foreach validate_section main start_mitmproxy
}
stop_service() {
cleanup_iptables
"$PROG" service-stop
}
reload_service() {
@ -134,20 +36,9 @@ reload_service() {
}
service_triggers() {
procd_add_reload_trigger "mitmproxy"
procd_add_reload_trigger "$CONFIG"
}
status() {
if pgrep mitmweb >/dev/null 2>&1; then
echo "mitmproxy is running"
pgrep mitmweb
return 0
elif pgrep mitmdump >/dev/null 2>&1; then
echo "mitmdump is running"
pgrep mitmdump
return 0
else
echo "mitmproxy is not running"
return 1
fi
"$PROG" status
}

View File

@ -1,236 +1,463 @@
#!/bin/sh
#
# mitmproxyctl - mitmproxy management utility
# Copyright (C) 2025 CyberMind.fr (SecuBox)
#
# SecuBox mitmproxy manager - LXC container support
# Copyright (C) 2024 CyberMind.fr
CONF_DIR=/etc/mitmproxy
DATA_DIR=/tmp/mitmproxy
LOG_FILE=/tmp/mitmproxy/requests.log
CONFIG="mitmproxy"
LXC_NAME="mitmproxy"
OPKG_UPDATED=0
# Paths
LXC_PATH="/srv/lxc"
LXC_ROOTFS="$LXC_PATH/$LXC_NAME/rootfs"
LXC_CONFIG="$LXC_PATH/$LXC_NAME/config"
usage() {
cat <<EOF
mitmproxyctl - mitmproxy management utility
Usage: mitmproxyctl <command> [options]
cat <<'EOF'
Usage: mitmproxyctl <command>
Commands:
status Show service status
start Start mitmproxy
stop Stop mitmproxy
restart Restart mitmproxy
enable Enable at boot
disable Disable at boot
logs Show recent logs
flows List captured flows
clear Clear captured data
ca-cert Show CA certificate path
install-ca Install CA cert instructions
stats Show traffic statistics
install Install prerequisites and create LXC container
check Run prerequisite checks
update Update mitmproxy in container
status Show container status
logs Show mitmproxy logs (use -f to follow)
shell Open shell in container
cert Show CA certificate info / export path
service-run Internal: run container under procd
service-stop Stop container
Options:
-h, --help Show this help message
Modes (configure in /etc/config/mitmproxy):
regular - Standard HTTP/HTTPS proxy (default)
transparent - Transparent proxy (requires iptables redirect)
upstream - Forward to upstream proxy
reverse - Reverse proxy mode
Web Interface: http://<router-ip>:8081
Proxy Port: 8080
EOF
}
require_root() { [ "$(id -u)" -eq 0 ] || { echo "Root required" >&2; exit 1; }; }
log_info() { echo "[INFO] $*"; }
log_warn() { echo "[WARN] $*" >&2; }
log_error() { echo "[ERROR] $*" >&2; }
uci_get() { uci -q get ${CONFIG}.main.$1; }
uci_set() { uci set ${CONFIG}.main.$1="$2" && uci commit ${CONFIG}; }
# Load configuration with defaults
load_config() {
proxy_port="$(uci_get proxy_port || echo 8080)"
web_port="$(uci_get web_port || echo 8081)"
web_host="$(uci_get web_host || echo 0.0.0.0)"
data_path="$(uci_get data_path || echo /srv/mitmproxy)"
memory_limit="$(uci_get memory_limit || echo 256M)"
mode="$(uci_get mode || echo regular)"
upstream_proxy="$(uci_get upstream_proxy || echo '')"
reverse_target="$(uci_get reverse_target || echo '')"
ssl_insecure="$(uci_get ssl_insecure || echo 0)"
anticache="$(uci_get anticache || echo 0)"
anticomp="$(uci_get anticomp || echo 0)"
flow_detail="$(uci_get flow_detail || echo 1)"
}
ensure_dir() { [ -d "$1" ] || mkdir -p "$1"; }
has_lxc() {
command -v lxc-start >/dev/null 2>&1 && \
command -v lxc-stop >/dev/null 2>&1
}
# Ensure required packages are installed
ensure_packages() {
require_root
for pkg in "$@"; do
if ! opkg list-installed | grep -q "^$pkg "; then
if [ "$OPKG_UPDATED" -eq 0 ]; then
opkg update || return 1
OPKG_UPDATED=1
fi
opkg install "$pkg" || return 1
fi
done
}
lxc_check_prereqs() {
log_info "Checking LXC prerequisites..."
ensure_packages lxc lxc-common lxc-attach lxc-start lxc-stop lxc-destroy || return 1
if [ ! -d /sys/fs/cgroup ]; then
log_error "cgroups not mounted at /sys/fs/cgroup"
return 1
fi
log_info "LXC ready"
}
lxc_create_rootfs() {
load_config
if [ -d "$LXC_ROOTFS" ] && [ -f "$LXC_ROOTFS/etc/alpine-release" ]; then
log_info "LXC rootfs already exists"
return 0
fi
log_info "Creating LXC rootfs for mitmproxy..."
ensure_dir "$LXC_PATH/$LXC_NAME"
lxc_create_alpine_rootfs || return 1
lxc_create_config || return 1
log_info "LXC rootfs created successfully"
}
lxc_create_alpine_rootfs() {
local arch="aarch64"
local alpine_version="3.19"
local mirror="https://dl-cdn.alpinelinux.org/alpine"
local rootfs="$LXC_ROOTFS"
# Detect architecture
case "$(uname -m)" in
x86_64) arch="x86_64" ;;
aarch64) arch="aarch64" ;;
armv7l) arch="armv7" ;;
*) arch="x86_64" ;;
esac
log_info "Downloading Alpine Linux $alpine_version ($arch)..."
ensure_dir "$rootfs"
cd "$rootfs" || return 1
# Download Alpine minirootfs
local rootfs_url="$mirror/v$alpine_version/releases/$arch/alpine-minirootfs-$alpine_version.0-$arch.tar.gz"
wget -q -O /tmp/alpine-rootfs.tar.gz "$rootfs_url" || {
log_error "Failed to download Alpine rootfs"
return 1
}
# Extract rootfs
tar xzf /tmp/alpine-rootfs.tar.gz -C "$rootfs" || return 1
rm -f /tmp/alpine-rootfs.tar.gz
# Configure Alpine
echo "nameserver 8.8.8.8" > "$rootfs/etc/resolv.conf"
# Install mitmproxy in the container
cat > "$rootfs/tmp/setup-mitmproxy.sh" << 'SETUP'
#!/bin/sh
set -e
# Update and install dependencies
apk update
apk add --no-cache \
python3 \
py3-pip \
py3-wheel \
py3-cryptography \
py3-openssl \
py3-cffi \
py3-brotli \
py3-yaml \
py3-tornado \
py3-urwid \
libffi \
openssl \
ca-certificates
# Install mitmproxy via pip
pip3 install --break-system-packages mitmproxy
# Create directories
mkdir -p /data /var/log/mitmproxy
# Create startup script
cat > /opt/start-mitmproxy.sh << 'START'
#!/bin/sh
cd /data
# Read environment variables for configuration
MODE="${MITMPROXY_MODE:-regular}"
PROXY_PORT="${MITMPROXY_PROXY_PORT:-8080}"
WEB_PORT="${MITMPROXY_WEB_PORT:-8081}"
WEB_HOST="${MITMPROXY_WEB_HOST:-0.0.0.0}"
# Build command arguments
ARGS="--listen-host 0.0.0.0 --listen-port $PROXY_PORT"
ARGS="$ARGS --set confdir=/data"
# Mode-specific options
case "$MODE" in
transparent)
ARGS="$ARGS --mode transparent"
;;
upstream)
[ -n "$UPSTREAM_PROXY" ] && ARGS="$ARGS --mode upstream:$UPSTREAM_PROXY"
;;
reverse)
[ -n "$REVERSE_TARGET" ] && ARGS="$ARGS --mode reverse:$REVERSE_TARGET"
;;
esac
# Optional flags
[ "$SSL_INSECURE" = "1" ] && ARGS="$ARGS --ssl-insecure"
[ "$ANTICACHE" = "1" ] && ARGS="$ARGS --anticache"
[ "$ANTICOMP" = "1" ] && ARGS="$ARGS --anticomp"
[ -n "$FLOW_DETAIL" ] && ARGS="$ARGS --flow-detail $FLOW_DETAIL"
# Run mitmweb (web interface + proxy)
exec mitmweb $ARGS --web-host "$WEB_HOST" --web-port "$WEB_PORT" --no-web-open-browser
START
chmod +x /opt/start-mitmproxy.sh
echo "mitmproxy installed successfully"
SETUP
chmod +x "$rootfs/tmp/setup-mitmproxy.sh"
# Run setup in chroot
log_info "Installing mitmproxy in container (this may take a while)..."
chroot "$rootfs" /tmp/setup-mitmproxy.sh || {
log_error "Failed to install mitmproxy in container"
return 1
}
rm -f "$rootfs/tmp/setup-mitmproxy.sh"
}
lxc_create_config() {
load_config
cat > "$LXC_CONFIG" << EOF
# mitmproxy LXC Configuration
lxc.uts.name = $LXC_NAME
# Root filesystem
lxc.rootfs.path = dir:$LXC_ROOTFS
# Network - use host network for simplicity
lxc.net.0.type = none
# Mounts
lxc.mount.auto = proc:mixed sys:ro cgroup:mixed
lxc.mount.entry = $data_path data none bind,create=dir 0 0
# Environment variables for configuration
lxc.environment = MITMPROXY_MODE=$mode
lxc.environment = MITMPROXY_PROXY_PORT=$proxy_port
lxc.environment = MITMPROXY_WEB_PORT=$web_port
lxc.environment = MITMPROXY_WEB_HOST=$web_host
lxc.environment = UPSTREAM_PROXY=$upstream_proxy
lxc.environment = REVERSE_TARGET=$reverse_target
lxc.environment = SSL_INSECURE=$ssl_insecure
lxc.environment = ANTICACHE=$anticache
lxc.environment = ANTICOMP=$anticomp
lxc.environment = FLOW_DETAIL=$flow_detail
# Capabilities
lxc.cap.drop = sys_admin sys_module mac_admin mac_override
# cgroups limits
lxc.cgroup.memory.limit_in_bytes = $memory_limit
# Init
lxc.init.cmd = /opt/start-mitmproxy.sh
# Console
lxc.console.size = 1024
lxc.pty.max = 1024
EOF
log_info "LXC config created at $LXC_CONFIG"
}
lxc_stop() {
if lxc-info -n "$LXC_NAME" >/dev/null 2>&1; then
lxc-stop -n "$LXC_NAME" -k >/dev/null 2>&1 || true
fi
}
lxc_run() {
load_config
lxc_stop
if [ ! -f "$LXC_CONFIG" ]; then
log_error "LXC not configured. Run 'mitmproxyctl install' first."
return 1
fi
# Regenerate config to pick up any UCI changes
lxc_create_config
# Ensure mount points exist
ensure_dir "$data_path"
log_info "Starting mitmproxy LXC container..."
log_info "Web interface: http://0.0.0.0:$web_port"
log_info "Proxy port: $proxy_port"
exec lxc-start -n "$LXC_NAME" -F -f "$LXC_CONFIG"
}
lxc_status() {
if lxc-info -n "$LXC_NAME" >/dev/null 2>&1; then
lxc-info -n "$LXC_NAME"
else
echo "LXC container '$LXC_NAME' not found or not configured"
fi
}
lxc_logs() {
load_config
local logfile="$LXC_ROOTFS/var/log/mitmproxy/mitmproxy.log"
if lxc-info -n "$LXC_NAME" -s 2>/dev/null | grep -q "RUNNING"; then
# For mitmweb, logs go to stderr which procd captures
if [ "$1" = "-f" ]; then
logread -f -e mitmproxy
else
logread -e mitmproxy | tail -100
fi
elif [ -f "$logfile" ]; then
if [ "$1" = "-f" ]; then
tail -f "$logfile"
else
tail -100 "$logfile"
fi
else
log_warn "Container not running. Try: logread -e mitmproxy"
fi
}
lxc_shell() {
lxc-attach -n "$LXC_NAME" -- /bin/sh
}
lxc_destroy() {
lxc_stop
if [ -d "$LXC_PATH/$LXC_NAME" ]; then
rm -rf "$LXC_PATH/$LXC_NAME"
log_info "LXC container destroyed"
fi
}
cmd_install() {
require_root
load_config
if ! has_lxc; then
log_error "LXC not available. Install lxc packages first."
exit 1
fi
log_info "Installing mitmproxy..."
# Create directories
ensure_dir "$data_path"
lxc_check_prereqs || exit 1
lxc_create_rootfs || exit 1
uci_set enabled '1'
/etc/init.d/mitmproxy enable
log_info "mitmproxy installed."
log_info "Start with: /etc/init.d/mitmproxy start"
log_info "Web interface: http://<router-ip>:$web_port"
log_info "Proxy port: $proxy_port"
}
cmd_check() {
load_config
log_info "Checking prerequisites..."
if has_lxc; then
log_info "LXC: available"
lxc_check_prereqs
else
log_warn "LXC: not available"
fi
}
cmd_update() {
require_root
load_config
log_info "Updating mitmproxy..."
lxc_destroy
lxc_create_rootfs || exit 1
if /etc/init.d/mitmproxy enabled >/dev/null 2>&1; then
/etc/init.d/mitmproxy restart
else
log_info "Update complete. Restart manually to apply."
fi
}
cmd_status() {
if pgrep mitmweb >/dev/null 2>&1; then
echo "Status: Running (mitmweb)"
echo "PID: $(pgrep mitmweb)"
echo "Web UI: http://$(uci -q get network.lan.ipaddr || echo '192.168.1.1'):$(uci -q get mitmproxy.main.web_port || echo '8081')"
elif pgrep mitmdump >/dev/null 2>&1; then
echo "Status: Running (mitmdump)"
echo "PID: $(pgrep mitmdump)"
else
echo "Status: Stopped"
fi
echo ""
echo "Configuration:"
echo " Mode: $(uci -q get mitmproxy.main.mode || echo 'transparent')"
echo " Listen: $(uci -q get mitmproxy.main.listen_host || echo '0.0.0.0'):$(uci -q get mitmproxy.main.listen_port || echo '8080')"
echo " Enabled: $(uci -q get mitmproxy.main.enabled || echo '0')"
}
cmd_start() {
echo "Starting mitmproxy..."
/etc/init.d/mitmproxy start
}
cmd_stop() {
echo "Stopping mitmproxy..."
/etc/init.d/mitmproxy stop
}
cmd_restart() {
echo "Restarting mitmproxy..."
/etc/init.d/mitmproxy restart
}
cmd_enable() {
uci set mitmproxy.main.enabled='1'
uci commit mitmproxy
/etc/init.d/mitmproxy enable
echo "mitmproxy enabled at boot"
}
cmd_disable() {
uci set mitmproxy.main.enabled='0'
uci commit mitmproxy
/etc/init.d/mitmproxy disable
echo "mitmproxy disabled at boot"
lxc_status
}
cmd_logs() {
if [ -f "$LOG_FILE" ]; then
tail -50 "$LOG_FILE"
lxc_logs "$@"
}
cmd_shell() {
lxc_shell
}
cmd_cert() {
load_config
local cert_path="$data_path/mitmproxy-ca-cert.pem"
if [ -f "$cert_path" ]; then
log_info "CA Certificate location: $cert_path"
log_info ""
log_info "To install on clients:"
log_info " 1. Download from: http://<router-ip>:$web_port/cert/pem"
log_info " 2. Or copy: $cert_path"
log_info ""
log_info "Certificate info:"
openssl x509 -in "$cert_path" -noout -subject -dates 2>/dev/null || \
cat "$cert_path"
else
echo "No logs available at $LOG_FILE"
log_warn "CA certificate not yet generated."
log_info "Start mitmproxy first: /etc/init.d/mitmproxy start"
log_info "Then access: http://<router-ip>:$web_port/cert"
fi
}
cmd_flows() {
local flow_file=$(uci -q get mitmproxy.capture.flow_file || echo "/tmp/mitmproxy/flows.bin")
if [ -f "$flow_file" ]; then
echo "Flow file: $flow_file"
echo "Size: $(ls -lh "$flow_file" | awk '{print $5}')"
echo ""
echo "Use 'mitmproxy -r $flow_file' to replay flows"
else
echo "No flow file found"
fi
}
cmd_service_run() {
require_root
load_config
cmd_clear() {
echo "Clearing captured data..."
rm -f "$DATA_DIR"/*.log "$DATA_DIR"/*.bin
echo "Done"
}
cmd_ca_cert() {
local cert="$CONF_DIR/mitmproxy-ca-cert.pem"
if [ -f "$cert" ]; then
echo "CA Certificate: $cert"
echo ""
echo "Certificate details:"
openssl x509 -in "$cert" -noout -subject -issuer -dates 2>/dev/null || \
cat "$cert"
else
echo "CA certificate not found"
echo "Start mitmproxy once to generate the certificate"
fi
}
cmd_install_ca() {
local cert="$CONF_DIR/mitmproxy-ca-cert.pem"
local router_ip=$(uci -q get network.lan.ipaddr || echo "192.168.1.1")
cat <<EOF
=== Installing mitmproxy CA Certificate ===
To intercept HTTPS traffic, clients must trust the mitmproxy CA.
1. Access the certificate at:
http://$router_ip:$(uci -q get mitmproxy.main.web_port || echo '8081')/cert
2. Or download directly:
scp root@$router_ip:$cert ./mitmproxy-ca.pem
3. Install on devices:
Windows:
- Double-click the .pem file
- Install to "Trusted Root Certification Authorities"
macOS:
- Double-click to add to Keychain
- In Keychain Access, find the cert and set "Always Trust"
Linux:
- Copy to /usr/local/share/ca-certificates/
- Run: sudo update-ca-certificates
Android:
- Settings > Security > Install from storage
- Select the certificate file
iOS:
- Email the cert and open it
- Settings > General > Profile > Install
- Settings > General > About > Certificate Trust Settings
EOF
}
cmd_stats() {
echo "=== mitmproxy Statistics ==="
echo ""
if [ -f "$LOG_FILE" ]; then
local total=$(wc -l < "$LOG_FILE" 2>/dev/null || echo "0")
echo "Total requests logged: $total"
if command -v jq >/dev/null 2>&1; then
echo ""
echo "Top 10 hosts:"
jq -r '.request.host // .host // "unknown"' "$LOG_FILE" 2>/dev/null | \
sort | uniq -c | sort -rn | head -10
echo ""
echo "Request methods:"
jq -r '.request.method // .method // "GET"' "$LOG_FILE" 2>/dev/null | \
sort | uniq -c | sort -rn
fi
else
echo "No statistics available"
fi
}
# Parse arguments
case "$1" in
status)
cmd_status
;;
start)
cmd_start
;;
stop)
cmd_stop
;;
restart)
cmd_restart
;;
enable)
cmd_enable
;;
disable)
cmd_disable
;;
logs)
cmd_logs
;;
flows)
cmd_flows
;;
clear)
cmd_clear
;;
ca-cert|ca|cert)
cmd_ca_cert
;;
install-ca|install)
cmd_install_ca
;;
stats|statistics)
cmd_stats
;;
-h|--help|help)
usage
;;
*)
usage
if ! has_lxc; then
log_error "LXC not available"
exit 1
;;
esac
fi
exit 0
lxc_check_prereqs || exit 1
lxc_run
}
cmd_service_stop() {
require_root
lxc_stop
}
# Main Entry Point
case "${1:-}" in
install) shift; cmd_install "$@" ;;
check) shift; cmd_check "$@" ;;
update) shift; cmd_update "$@" ;;
status) shift; cmd_status "$@" ;;
logs) shift; cmd_logs "$@" ;;
shell) shift; cmd_shell "$@" ;;
cert) shift; cmd_cert "$@" ;;
service-run) shift; cmd_service_run "$@" ;;
service-stop) shift; cmd_service_stop "$@" ;;
help|--help|-h|'') usage ;;
*) echo "Unknown command: $1" >&2; usage >&2; exit 1 ;;
esac