Skip to content

Instantly share code, notes, and snippets.

@MohamedElashri
Last active October 6, 2025 00:42
Show Gist options
  • Select an option

  • Save MohamedElashri/b051792140e4f3ad66f20e25df6e9119 to your computer and use it in GitHub Desktop.

Select an option

Save MohamedElashri/b051792140e4f3ad66f20e25df6e9119 to your computer and use it in GitHub Desktop.

Revisions

  1. MohamedElashri revised this gist Oct 6, 2025. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions ssid-dns
    Original file line number Diff line number Diff line change
    @@ -2,8 +2,8 @@
    set -euo pipefail

    # --- Policy ---
    HOME_SSIDS=("BarHen" "BarNad") # home Wi-Fi names
    CERN_SSID_REGEX='^(CERN|eduroam|CERN-Visitor|CERN-Trusted)$'
    HOME_SSIDS=("HomeNetworkI" "HomeNetworkII") # home Wi-Fi names
    CERN_SSID_REGEX='^(CERN|eduroam|CERN-Visitor)$'
    CERN_DNS="137.138.16.5 137.138.17.5"
    FALLBACK_DNS="9.9.9.9"

  2. MohamedElashri revised this gist Oct 5, 2025. 1 changed file with 20 additions and 0 deletions.
    20 changes: 20 additions & 0 deletions com.melashri.ssid-dns.plist
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
    "http://www.apple.com/DTDs/PropertyList-1.0.dtd"\>
    <plist version="1.0">
    <dict>
    <key>Label</key><string>com.melashri.ssid-dns</string>
    <key>ProgramArguments</key>
    <array>
    <string>/Users/melashri/.local/bin/ssid-dns</string>
    </array>
    <key>RunAtLoad</key><true/>
    <key>KeepAlive</key>
    <dict>
    <key>NetworkState</key><true/>
    </dict>
    <key>StartInterval</key><integer>60</integer>
    <key>StandardOutPath</key><string>/tmp/ssid-dns.out</string>
    <key>StandardErrorPath</key><string>/tmp/ssid-dns.err</string>
    </dict>
    </plist>
  3. MohamedElashri created this gist Oct 5, 2025.
    160 changes: 160 additions & 0 deletions ssid-dns
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,160 @@
    #!/usr/bin/env bash
    set -euo pipefail

    # --- Policy ---
    HOME_SSIDS=("BarHen" "BarNad") # home Wi-Fi names
    CERN_SSID_REGEX='^(CERN|eduroam|CERN-Visitor|CERN-Trusted)$'
    CERN_DNS="137.138.16.5 137.138.17.5"
    FALLBACK_DNS="9.9.9.9"

    # CERN network ranges (add as needed)
    CERN_NETS=( "137.138.0.0/16" "128.142.0.0/16" "188.184.0.0/15" "194.12.128.0/17" )

    # --- Helpers ---
    get_wifi_device() {
    /usr/sbin/networksetup -listallhardwareports | awk '
    /^Hardware Port: (Wi-Fi|AirPort)$/ {f=1; next}
    f && /^Device:/ {print $2; exit}
    '
    }
    get_service_for_device() {
    local dev="$1"
    /usr/sbin/networksetup -listnetworkserviceorder | awk -v d="$dev" '
    /^\([0-9]+\)/ {svc=$0; sub(/^\([0-9]+\) /,"",svc); gsub(/[[:space:]]+$/,"",svc)}
    /Device: / && $0 ~ "Device: " d {print svc; exit}
    '
    }
    get_default_if() {
    /sbin/route -n get default 2>/dev/null | awk '/interface:/{print $2; exit}'
    }
    get_gateway_ip() {
    /sbin/route -n get default 2>/dev/null | awk '/gateway:/{print $2; exit}'
    }
    cidr_match() { # cidr_match <ip> <cidr>
    python3 - "$1" "$2" <<'PY'
    import ipaddress,sys
    try:
    print(ipaddress.ip_address(sys.argv[1]) in ipaddress.ip_network(sys.argv[2], strict=False))
    except Exception:
    print(False)
    PY
    }
    get_search_domains() {
    /usr/sbin/scutil --dns | awk -F': ' '
    /^resolver #[0-9]+$/ {blk=1; next}
    blk && NF==0 {blk=0}
    blk && /^[[:space:]]*search domain/ {print $2}
    blk && /^[[:space:]]*domain/ {print $2}
    ' | sed 's/[[:space:]]*$//'
    }
    get_ssid() {
    local ssid dev
    dev="$(get_wifi_device || true)"

    # 0) networksetup with device (handles most cases)
    if [[ -n "${dev:-}" ]]; then
    if out=$(/usr/sbin/networksetup -getairportnetwork "$dev" 2>/dev/null); then
    # "Current Wi-Fi Network: <SSID>" or "You are not associated ..."
    if [[ "$out" =~ ^Current[[:space:]]Wi-?Fi[[:space:]]Network:\ (.*)$ ]]; then
    printf '%s\n' "${BASH_REMATCH[1]}"; return 0
    fi
    fi
    fi

    # 1) system_profiler
    ssid="$(/usr/sbin/system_profiler SPAirPortDataType 2>/dev/null | awk '
    /Current Network Information:/ {f=1; next}
    f && /^[[:space:]]*SSID:/ {sub(/^[[:space:]]*SSID:[[:space:]]*/,""); print; exit}
    f && NF==0 {f=0}
    ')"
    [[ -n "${ssid:-}" ]] && { printf '%s\n' "$ssid"; return 0; }

    # 2) ioreg
    ssid="$(/usr/sbin/ioreg -l | awk -F\" '/SSID_STR/ {print $4; exit}')"
    [[ -n "${ssid:-}" ]] && { printf '%s\n' "$ssid"; return 0; }

    # 3) scutil --nwi
    ssid="$(/usr/sbin/scutil --nwi 2>/dev/null | awk -F': ' '/SSID:/ {print $2; exit}')"
    [[ -n "${ssid:-}" ]] && { printf '%s\n' "$ssid"; return 0; }

    # 4) airport fallbacks
    for p in \
    /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport \
    /System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport \
    /System/Library/PrivateFrameworks/AppleWiFi.framework/Versions/Current/Resources/airport
    do
    [[ -x "$p" ]] || continue
    ssid="$("$p" -I 2>/dev/null | awk -F': ' '/ SSID/ {print $2; exit}')"
    [[ -n "${ssid:-}" ]] && { printf '%s\n' "$ssid"; return 0; }
    done

    return 1
    }

    get_current_dns() {
    /usr/sbin/networksetup -getdnsservers "$1" 2>/dev/null | awk '
    /^There (are|aren.t) any DNS Servers/ {print "Empty"; exit}
    {print}
    ' | paste -sd' ' -
    }
    set_dns_if_needed() {
    local service="$1" target="$2" current
    current="$(get_current_dns "$service")"
    if [[ "$target" == "$current" ]]; then
    echo "[dns] No change ($current) on $service"
    return
    fi
    if [[ "$target" == "Empty" ]]; then
    /usr/sbin/networksetup -setdnsservers "$service" Empty
    else
    # shellcheck disable=SC2086
    /usr/sbin/networksetup -setdnsservers "$service" $target
    fi
    echo "[dns] Applied: $target on $service"
    }

    # --- Detect environment ---
    wifi_dev="$(get_wifi_device || true)"
    def_if="$(get_default_if || true)"
    prim_svc="$(get_service_for_device "${def_if:-}" || true)"
    ssid="$(get_ssid || true)"
    gw="$(get_gateway_ip || true)"
    domains="$(get_search_domains || true)"

    # CERN heuristics (any true -> use CERN DNS)
    cern_ssid=false
    cern_gw=false
    cern_domain=false
    [[ -n "${ssid:-}" && "$ssid" =~ $CERN_SSID_REGEX ]] && cern_ssid=true
    if [[ -n "${gw:-}" ]]; then
    for net in "${CERN_NETS[@]}"; do
    if [[ "$(cidr_match "$gw" "$net")" == "True" ]]; then cern_gw=true; break; fi
    done
    fi
    if printf '%s\n' "$domains" | grep -qiE '(^|[[:space:]])([^.]*\.)?cern\.ch$'; then cern_domain=true; fi

    echo "[ssid-dns] def_if=${def_if:-?} prim_svc=${prim_svc:-?} ssid=${ssid:-<none>} gw=${gw:-<none>}"
    echo "[ssid-dns] domains: $(printf '%s' "$domains" | tr '\n' ' | ')"
    echo "[ssid-dns] flags: CERN_SSID=$cern_ssid CERN_GW=$cern_gw CERN_DOMAIN=$cern_domain"

    # --- Decide target DNS ---
    target="$FALLBACK_DNS" # default
    if [[ -n "${ssid:-}" ]] && printf '%s\n' "${HOME_SSIDS[@]}" | grep -qx -- "$ssid"; then
    target="Empty" # home Wi-Fi -> router DNS
    elif $cern_ssid || $cern_gw || $cern_domain; then
    target="$CERN_DNS" # CERN -> CERN DNS
    fi

    # --- Apply ---
    if [[ -n "${prim_svc:-}" ]]; then
    set_dns_if_needed "$prim_svc" "$target"
    else
    echo "[dns] Could not resolve primary service; skipping change."
    fi

    # --- Show effective default resolver (resolver #1) ---
    /usr/sbin/scutil --dns | awk '
    $0=="resolver #1" {f=1; next}
    f && NF==0 {f=0}
    f && /nameserver\[/ {print}
    '