Created
April 16, 2026 02:59
-
-
Save fadlee/8a2d79243e09a31e47c811240e19a2b6 to your computer and use it in GitHub Desktop.
Script to switch server wifi safely
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -Eeuo pipefail | |
| INTERFACE="${INTERFACE:-wlp1s0}" | |
| TARGET_SSID="${TARGET_SSID:-CHANGE_ME_SSID}" | |
| TARGET_PASSWORD="${TARGET_PASSWORD:-CHANGE_ME_PASSWORD}" | |
| TARGET_BSSID="${TARGET_BSSID:-}" | |
| ROLLBACK_DELAY="${ROLLBACK_DELAY:-45}" | |
| VERIFY_SECONDS="${VERIFY_SECONDS:-25}" | |
| PING_HOST="${PING_HOST:-1.1.1.1}" | |
| ROLLBACK_PID="" | |
| ROLLBACK_FILE="" | |
| log() { | |
| printf '[%s] %s\n' "$(date '+%F %T')" "$*" | |
| } | |
| fail() { | |
| log "ERROR: $*" | |
| exit 1 | |
| } | |
| require_root() { | |
| [[ "${EUID}" -eq 0 ]] || fail "run as root" | |
| } | |
| require_cmd() { | |
| command -v "$1" >/dev/null 2>&1 || fail "missing command: $1" | |
| } | |
| current_connection() { | |
| nmcli -t -f GENERAL.CONNECTION device show "$INTERFACE" 2>/dev/null | head -n1 | cut -d: -f2- | |
| } | |
| connection_exists() { | |
| local name="$1" | |
| [[ -n "$name" && "$name" != "--" ]] || return 1 | |
| nmcli -t -f NAME connection show | grep -Fxq "$name" | |
| } | |
| is_healthy() { | |
| local state="" | |
| state=$(nmcli -t -f GENERAL.STATE device show "$INTERFACE" 2>/dev/null | head -n1 | cut -d: -f2-) | |
| [[ "$state" == "100 (connected)" ]] || return 1 | |
| ping -I "$INTERFACE" -c 1 -W 3 "$PING_HOST" >/dev/null 2>&1 | |
| } | |
| wait_for_health() { | |
| local seconds="$1" | |
| local deadline=$((SECONDS + seconds)) | |
| while ((SECONDS < deadline)); do | |
| if is_healthy; then | |
| return 0 | |
| fi | |
| sleep 2 | |
| done | |
| return 1 | |
| } | |
| start_rollback_timer() { | |
| local previous="$1" | |
| connection_exists "$previous" || fail "previous connection not found: $previous" | |
| ROLLBACK_FILE="/tmp/wifi-rollback-${INTERFACE}.flag" | |
| printf 'armed\n' >"$ROLLBACK_FILE" | |
| ( | |
| sleep "$ROLLBACK_DELAY" | |
| if [[ -f "$ROLLBACK_FILE" ]]; then | |
| logger -t switch-wifi "rollback timer fired; restoring [$previous] on [$INTERFACE]" | |
| nmcli connection up "$previous" ifname "$INTERFACE" >/tmp/switch-wifi-rollback.log 2>&1 || true | |
| fi | |
| ) & | |
| ROLLBACK_PID=$! | |
| log "Rollback armed: ${ROLLBACK_DELAY}s, pid=$ROLLBACK_PID" | |
| } | |
| disarm_rollback_timer() { | |
| [[ -n "${ROLLBACK_FILE:-}" && -f "${ROLLBACK_FILE:-}" ]] && rm -f "$ROLLBACK_FILE" || true | |
| if [[ -n "${ROLLBACK_PID:-}" ]]; then | |
| kill "$ROLLBACK_PID" >/dev/null 2>&1 || true | |
| wait "$ROLLBACK_PID" 2>/dev/null || true | |
| fi | |
| log "Rollback disarmed" | |
| } | |
| restore_previous_now() { | |
| local previous="$1" | |
| connection_exists "$previous" || fail "cannot restore previous connection: $previous" | |
| log "Restoring previous connection now: $previous" | |
| nmcli connection up "$previous" ifname "$INTERFACE" | |
| } | |
| cleanup_on_exit() { | |
| local ec=$? | |
| if ((ec != 0)); then | |
| log "Script exit non-zero ($ec). Rollback remains armed if timer exists" | |
| fi | |
| } | |
| trap cleanup_on_exit EXIT | |
| main() { | |
| require_root | |
| require_cmd nmcli | |
| require_cmd ping | |
| require_cmd logger | |
| [[ "$TARGET_SSID" != "CHANGE_ME_SSID" ]] || fail "set TARGET_SSID first" | |
| [[ "$TARGET_PASSWORD" != "CHANGE_ME_PASSWORD" ]] || fail "set TARGET_PASSWORD first" | |
| local previous | |
| previous=$(current_connection) | |
| connection_exists "$previous" || fail "no valid current connection to fallback to" | |
| log "Current connection: $previous" | |
| log "Target SSID: $TARGET_SSID" | |
| [[ -n "$TARGET_BSSID" ]] && log "Target BSSID: $TARGET_BSSID" | |
| nmcli device wifi rescan ifname "$INTERFACE" >/dev/null 2>&1 || true | |
| start_rollback_timer "$previous" | |
| local -a cmd=(nmcli device wifi connect "$TARGET_SSID" password "$TARGET_PASSWORD" ifname "$INTERFACE") | |
| [[ -n "$TARGET_BSSID" ]] && cmd+=(bssid "$TARGET_BSSID") | |
| log "Connecting to target Wi-Fi" | |
| if ! "${cmd[@]}"; then | |
| log "Target connect command failed" | |
| restore_previous_now "$previous" | |
| wait_for_health "$VERIFY_SECONDS" || fail "fallback attempted but health check failed" | |
| disarm_rollback_timer | |
| fail "restored previous connection after immediate connect failure" | |
| fi | |
| log "Connect command accepted. Verifying health" | |
| if wait_for_health "$VERIFY_SECONDS"; then | |
| log "Target Wi-Fi healthy" | |
| disarm_rollback_timer | |
| exit 0 | |
| fi | |
| log "Target Wi-Fi not healthy in time. Immediate fallback" | |
| restore_previous_now "$previous" | |
| wait_for_health "$VERIFY_SECONDS" || fail "fallback attempted but health check failed" | |
| disarm_rollback_timer | |
| fail "restored previous connection after failed verification" | |
| } | |
| main "$@" |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Cara pakai:
Kalau mau pakai BSSID spesifik: