- 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.
237 lines
8.3 KiB
Bash
Executable File
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 ===" |