Files
captive_portal-check/99-captive-portal
Pascal Bouquet 91126707cb fix: force proxy bypass for captive portal detection
- Firefox ignored `no_proxy` environment variables when a manual 
  proxy was configured in the user profile.
- Switched to using a temporary profile with `--no-remote` to 
  guarantee a clean state without proxy settings.
- Added automatic cleanup for the temporary profile directory.
- Updated user session detection to be more robust on LMDE 7 / Debian 13.
2026-02-17 18:32:11 +01:00

237 lines
8.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# =============================================================================
# NetworkManager Captive Portal Auto-Detector
# =============================================================================
# Erstellt von Pascal Bouquet am 16.09.2025
# Aktualisiert am 17.02.2026
#
# Dieses Skript ist freie Software: Es kann frei verwendet, bearbeitet und
# verbreitet werden. Es wird keine Garantie für die Funktionsfähigekeit übernommen.
# =============================================================================
# =============================================================================
# KONFIGURATION
# =============================================================================
LOG_FILE="/var/log/nm-captive.log"
LOG_LEVEL="INFO" # NONE, DEBUG, INFO, WARNING, ERROR
CHECK_INTERVAL=300 # 5 Minuten in Sekunden
MAX_CHECKS=12 # Maximal 1 Stunde lang prüfen (12 * 5min)
# Test-URLs für Captive Portal Erkennung
TEST_URLS=(
"http://captive.apple.com/hotspot-detect.html"
"http://connectivitycheck.gstatic.com/generate_204"
)
# =============================================================================
# FUNKTIONEN
# =============================================================================
log() {
local level=$1
local message=$2
# Kein Logging wenn LOG_LEVEL=NONE
if [ "$LOG_LEVEL" = "NONE" ]; then
return
fi
# Log-Level Filterung
case $LOG_LEVEL in
"DEBUG") echo "$(date '+%Y-%m-%d %H:%M:%S') - $level - $message" >> "$LOG_FILE" ;;
"INFO")
if [[ "$level" != "DEBUG" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - $level - $message" >> "$LOG_FILE"
fi
;;
"WARNING")
if [[ "$level" == "WARNING" || "$level" == "ERROR" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - $level - $message" >> "$LOG_FILE"
fi
;;
"ERROR")
if [[ "$level" == "ERROR" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - $level - $message" >> "$LOG_FILE"
fi
;;
esac
}
get_user_environment() {
local user=$1
local user_id=$(id -u "$user")
# Finde den Desktop-Prozess und übernehme dessen Environment
local pid=$(pgrep -u "$user" -n plasmashell || pgrep -u "$user" -n gnome-shell || pgrep -u "$user" -n kwin_wayland || echo "")
if [ -n "$pid" ] && [ -f "/proc/$pid/environ" ]; then
log "DEBUG" "Using environment from process $pid"
# Extrahiere alle benötigten Environment-Variablen
tr '\0' '\n' < "/proc/$pid/environ" | grep -E "(WAYLAND|DISPLAY|XDG|DBUS|USER|HOME|PATH)"
else
# Fallback: Basis-Environment setzen
log "DEBUG" "Using fallback environment"
echo "USER=$user"
echo "HOME=/home/$user"
echo "XDG_RUNTIME_DIR=/run/user/$user_id"
echo "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$user_id/bus"
# Versuche, den echten Display zu finden
if [ -S "/run/user/$user_id/wayland-0" ]; then
echo "WAYLAND_DISPLAY=wayland-0"
echo "XDG_SESSION_TYPE=wayland"
elif [ -S "/tmp/.X11-unix/X0" ]; then
echo "DISPLAY=:0"
else
echo "DISPLAY=:0"
fi
fi
}
get_user_session() {
local user=$(loginctl list-users | grep -v "UID" | head -n1 | awk '{print $2}')
local user_id=$(id -u "$user")
local display=":0"
local session_type="x11"
if [ -S "/run/user/$user_id/wayland-0" ]; then
display="wayland-0"
session_type="wayland"
fi
echo "$user $display $session_type"
}
check_captive_portal() {
local captive_detected=false
for url in "${TEST_URLS[@]}"; do
log "DEBUG" "Testing URL: $url"
if [[ "$url" == *"apple.com"* ]]; then
local response=$(curl -s -L --connect-timeout 5 "$url")
if [ $? -ne 0 ]; then
log "DEBUG" "Network error for $url"
captive_detected=true
break
elif ! echo "$response" | grep -qi "success"; then
log "DEBUG" "Apple check failed - no 'Success' in response"
captive_detected=true
break
fi
elif [[ "$url" == *"google"* || "$url" == *"gstatic"* ]]; then
local http_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 "$url")
if [ $? -ne 0 ]; then
log "DEBUG" "Network error for $url"
captive_detected=true
break
elif [ "$http_code" != "204" ]; then
log "DEBUG" "Google check failed - HTTP $http_code instead of 204"
captive_detected=true
break
fi
fi
done
if [ "$captive_detected" = true ]; then
log "INFO" "Captive portal detected"
return 1
else
log "INFO" "All connectivity checks passed - no captive portal"
return 0
fi
}
start_firefox() {
local user=$1
local display=$2
local user_id=$(id -u "$user")
# Erstelle ein temporäres Verzeichnis für das Profil im RAM (tmpfs)
# Wir machen das als User, damit die Berechtigungen direkt stimmen
local temp_profile=$(sudo -u "$user" mktemp -d -p /tmp/ firefox-captive.XXXXXX)
log "INFO" "Starting Firefox with clean temp profile: $temp_profile"
# Startbefehl
sudo -u "$user" env \
DISPLAY="$display" \
WAYLAND_DISPLAY="$display" \
XDG_RUNTIME_DIR="/run/user/$user_id" \
DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$user_id/bus" \
/usr/bin/firefox \
--no-remote \
--profile "$temp_profile" \
--private-window "http://detectportal.firefox.com/canonical.html" &
local pid=$!
# Ein kleiner Hintergrund-Job, der das Temp-Verzeichnis nach Schließen von Firefox löscht
(
while ps -p $pid > /dev/null; do sleep 5; done
rm -rf "$temp_profile"
log "DEBUG" "Cleaned up temp profile $temp_profile"
) &
}
start_periodic_checks() {
local interface="$1"
local user="$2"
local display="$3"
local session_type="$4"
local check_count=0
log "INFO" "Starting periodic checks for $interface (every ${CHECK_INTERVAL}s)"
while [ $check_count -lt $MAX_CHECKS ]; do
sleep $CHECK_INTERVAL
((check_count++))
log "DEBUG" "Periodic check $check_count/$MAX_CHECKS for $interface"
if ! check_captive_portal; then
log "INFO" "Captive portal still active - re-opening browser"
if start_firefox "$user" "$display" "$session_type"; then
log "INFO" "Firefox re-opened successfully"
else
log "ERROR" "Failed to re-open Firefox"
fi
else
log "INFO" "Captive portal resolved - stopping periodic checks"
break
fi
done
log "INFO" "Periodic checks completed for $interface"
}
# =============================================================================
# HAUPTPROGRAMM
# =============================================================================
log "INFO" "=== Dispatch triggered: $1 $2 ==="
if [[ "$1" == wl* ]] && [ "$2" = "up" ]; then
sleep 3
if ! check_captive_portal; then
log "INFO" "CAPTIVE PORTAL DETECTED! Opening browser..."
read user display session_type <<< $(get_user_session)
if [ -n "$user" ] && [ -n "$display" ]; then
log "INFO" "Found user: $user, display: $display, type: $session_type"
# Starte Firefox
if start_firefox "$user" "$display" "$session_type"; then
log "INFO" "Firefox successfully launched"
# STARTE PERIODISCHE CHECKS IM HINTERGRUND
log "INFO" "Starting periodic checks in background..."
start_periodic_checks "$1" "$user" "$display" "$session_type" &
else
log "ERROR" "Failed to start Firefox"
fi
else
log "WARNING" "No local user or display found for GUI access"
fi
else
log "INFO" "No captive portal detected on connection start"
fi
elif [[ "$1" == wl* ]] && [ "$2" = "down" ]]; then
log "INFO" "WLAN interface $1 disconnected"
fi
log "INFO" "=== Completed ==="