#!/bin/bash # Fetch the public IP address into a cache file, for widgets/network.lua. # # Run from conky's ${execi} every 30 minutes. The draw hook must never make a # network call: a hung request would block the Cairo draw and freeze the whole # dashboard, and a residential address is stable for days anyway. # # Exits non-zero with a message on stderr when it cannot fetch, leaving any # existing cache untouched rather than replacing a good address with an error # page. set -u CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/udt" CACHE="$CACHE_DIR/pubip.txt" umask 077 mkdir -p "$CACHE_DIR" # The temp file sits in the same directory as the target: rename is only # atomic within a filesystem, and the widget reads this on its own 2s cadence. TMP="$CACHE.tmp.$$" trap 'rm -f "$TMP"' EXIT # --max-time, not just --connect-timeout: a server that accepts the connection # and then stalls would otherwise hold a curl process for as long as it likes. if ! IP=$(curl -fsS --max-time 10 https://ipinfo.io/ip 2>/dev/null); then echo "pubip-sample: fetch failed" >&2 exit 1 fi # Validate before writing. A captive portal, a rate-limit message and an error # page all arrive with a 200 and would otherwise be written to the cache and # drawn on the dashboard as though they were an address. IP=$(echo "$IP" | tr -d '[:space:]') if ! echo "$IP" | grep -qE '^([0-9]{1,3}\.){3}[0-9]{1,3}$'; then echo "pubip-sample: response is not an IPv4 address" >&2 exit 1 fi # The epoch travels with the address so the widget can refuse to show a stale # one. { echo "ip $IP" echo "fetched $(date +%s)" } > "$TMP" mv -f "$TMP" "$CACHE"