76 lines
2.5 KiB
Bash
76 lines
2.5 KiB
Bash
#!/usr/bin/env bash
|
|
# cf-ddns.sh - Cloudflare DDNS updater
|
|
set -euo pipefail
|
|
|
|
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
if [ -f "${DIR}/.env" ]; then
|
|
# shellcheck disable=SC1091
|
|
source "${DIR}/.env"
|
|
else
|
|
echo "$(date -Iseconds) ERROR: missing ${DIR}/.env (create from .env.example)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
: "${CF_API_TOKEN:?need CF_API_TOKEN in .env}"
|
|
: "${ZONE:?need ZONE in .env}"
|
|
: "${RECORDS:?need RECORDS in .env}"
|
|
: "${IP_URL:=https://ipv4.icanhazip.com}"
|
|
: "${PROXIED:=false}"
|
|
|
|
AUTH_HEADER="Authorization: Bearer ${CF_API_TOKEN}"
|
|
CT_HEADER="Content-Type: application/json"
|
|
|
|
log() { echo "$(date -Iseconds) $*"; }
|
|
|
|
IP=$(curl -fsS "${IP_URL}" | tr -d '[:space:]')
|
|
if [[ -z "${IP}" ]]; then
|
|
log "ERROR: could not determine public IP"
|
|
exit 1
|
|
fi
|
|
|
|
ZONE_ID=$(curl -fsS -X GET "https://api.cloudflare.com/client/v4/zones?name=${ZONE}" \
|
|
-H "${AUTH_HEADER}" -H "${CT_HEADER}" | jq -r '.result[0].id // empty')
|
|
|
|
if [[ -z "${ZONE_ID}" ]]; then
|
|
log "ERROR: zone not found: ${ZONE}"
|
|
exit 1
|
|
fi
|
|
|
|
IFS=',' read -r -a RECORD_ARR <<< "${RECORDS}"
|
|
for fullrec in "${RECORD_ARR[@]}"; do
|
|
rec=$(echo "${fullrec}" | xargs)
|
|
log "Processing ${rec}"
|
|
info=$(curl -fsS -X GET "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records?name=${rec}&type=A" \
|
|
-H "${AUTH_HEADER}" -H "${CT_HEADER}")
|
|
|
|
RECORD_ID=$(echo "$info" | jq -r '.result[0].id // empty')
|
|
CURRENT_CONTENT=$(echo "$info" | jq -r '.result[0].content // empty')
|
|
|
|
if [[ -z "${RECORD_ID}" ]]; then
|
|
log "Creating ${rec} -> ${IP}"
|
|
create_resp=$(curl -fsS -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \
|
|
-H "${AUTH_HEADER}" -H "${CT_HEADER}" \
|
|
--data "{\"type\":\"A\",\"name\":\"${rec}\",\"content\":\"${IP}\",\"ttl\":1,\"proxied\":${PROXIED}}")
|
|
ok=$(echo "$create_resp" | jq -r '.success // false')
|
|
if [[ "$ok" != "true" ]]; then
|
|
log "ERROR creating ${rec}: ${create_resp}"
|
|
else
|
|
log "Created ${rec}"
|
|
fi
|
|
else
|
|
if [[ "${CURRENT_CONTENT}" == "${IP}" ]]; then
|
|
log "${rec} unchanged (${IP})"
|
|
else
|
|
log "Updating ${rec} -> ${IP}"
|
|
upd_resp=$(curl -fsS -X PUT "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records/${RECORD_ID}" \
|
|
-H "${AUTH_HEADER}" -H "${CT_HEADER}" \
|
|
--data "{\"type\":\"A\",\"name\":\"${rec}\",\"content\":\"${IP}\",\"ttl\":1,\"proxied\":${PROXIED}}")
|
|
ok=$(echo "$upd_resp" | jq -r '.success // false')
|
|
if [[ "$ok" != "true" ]]; then
|
|
log "ERROR updating ${rec}: ${upd_resp}"
|
|
else
|
|
log "Updated ${rec}"
|
|
fi
|
|
fi
|
|
fi
|
|
done |