diff options
author | Freya Murphy <freya@freyacat.org> | 2025-07-30 11:50:23 -0400 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2025-07-30 11:50:23 -0400 |
commit | 896323f6210a4d033885d1c4f0e445ce7f8bb4a2 (patch) | |
tree | 67b8fbc7e6f3b422fd2e99ee94ef8d4c982ba078 | |
parent | update fconv (diff) | |
download | scripts-896323f6210a4d033885d1c4f0e445ce7f8bb4a2.tar.gz scripts-896323f6210a4d033885d1c4f0e445ce7f8bb4a2.tar.bz2 scripts-896323f6210a4d033885d1c4f0e445ce7f8bb4a2.zip |
update cfdns
-rwxr-xr-x | cfdns | 287 |
1 files changed, 113 insertions, 174 deletions
@@ -1,233 +1,172 @@ -#!/usr/bin/env bash +#!/bin/bash -quiet=0 # should i shut up?!?!? :< +API_TOKEN="${API_TOKEN:-ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcd}" +ZONE="${ZONE:-example.com}" +DOMAIN="${DOMAIN:-example.com}" -token="" # the api token -domain="" # the domain to update - -record="A" # the record type -ttl="60" # the new time to live -content="" # the new record content - -usage() { - printf "usage: cfdns [-hq] [-d DOMAIN] [-t TOKEN] [-r RECORD] [-l TTL] [-cC CONTENT]\n\n" - printf "\t-h\t\tshow the help message\n" - printf "\t-q\t\tquiet output\n" - printf "\t-d DOMAIN\tthe domain name to update\n" - printf "\t-t TOKEN\tthe api token\n" - printf "\t-r RECORD\tthe new record type\n" - printf "\t-l TTL\t\tthe new time to live\n" - printf "\t-c CONTENT\tthe new contents of the record\n" - printf "\t-C RAW CONTENT\tthe new conents of the record (as raw json)\n" +EVENT() { + printf "\x1b[95m>>> \x1b[0m\x1b[98m$1\n" } -chk_command() { - if ! command -v "$1" > /dev/null; then - >&2 echo "error: command '$1' could not be found" - exit 1 - fi -} - -chk_command "getopts" -chk_command "curl" -chk_command "jq" - -while getopts "hqd:t:r:l:c:C:" arg > /dev/null; do - case $arg in - h) - usage - exit 0 - ;; - q) - quiet=1 - ;; - d) - domain="${OPTARG}" - ;; - t) - token="${OPTARG}" - ;; - r) - record="${OPTARG}" - ;; - l) - ttl="${OPTARG}" - ;; - c) - content="\"content\": \"${OPTARG}\"" - ;; - C) - content="${OPTARG}" - ;; - ?) - exit 1 - ;; - esac -done - -if [ ! "$cert" = "cert.pem" ] && [ "$key" = "cert.key" ]; then - name=${cert%.*} - key="$name.key" -fi - -log() { - if [ $quiet = 0 ]; then - printf "$*\n" 1>&2 - fi +LOG() { + printf "\x1b[98m$1\n" } -step() { - if [ $quiet = 0 ]; then - printf "\033[32m>>> \033[0m$*\n" 1>&2 - fi +ERROR() { + >&2 printf "\x1b[91mError: \x1b[0m\x1b[98m$1\n" } -error() { - printf "\033[31merror: \033[0m$*\n" > /dev/stderr -} - -die() { - kill $$ -} - -handle_error() { - errs="$1" - count="$(echo $errs | jq -r ". | length")" - for i in $(seq 0 $(($count - 1))); do - err="$(echo $errs | jq -r ".[$i]")" - error "$(echo $err | jq -r '.message')" - chain="$(echo $err | jq -r '.error_chain')" - if ! [ "$chain" = "null" ]; then - count="$(echo $chain | jq -r ". | length")" - for j in $(seq 0 $(($count - 1))); do - error "$(echo $chain | jq -r ".[$j].message")" - done - fi - done -} - -_curl() { +CURL() { RESPONSE=$(curl --silent --request $1 \ --url "https://api.cloudflare.com/client/v4$2" \ --header "Content-Type: application/json" \ - --header "Authorization: Bearer $token" \ + --header "Authorization: Bearer $API_TOKEN" \ --data "$3") SUCCESS=$(echo $RESPONSE | jq -r ".success") if [ "$SUCCESS" != "true" ]; then - errs="$(echo $RESPONSE | jq -r .errors)" - handle_error "$errs" - die + ERROR "$(echo $RESPONSE | jq -r ".errors[0].message")" + kill $$ fi echo $RESPONSE | jq ".result" } -patch() { - _curl "PATCH" "$1" "$2" +PATCH() { + CURL "PATCH" "$1" "$2" } -post() { - _curl "POST" "$1" "$2" +POST() { + CURL "POST" "$1" "$2" } -get() { - _curl "GET" "$1" "" +GET() { + CURL "GET" "$1" "" } -# Step 1: get the zone the domain is in -zone=$(echo "$domain" | awk -F'.' '{print $(NF-1)"."$(NF);}' 2>/dev/null) - -if [ "$zone" = "" ]; then - error "invalid domain: '$domain'" - die -fi - -step "fetching zones..." -zones=$(get "/zones") -zone_id="null" +EVENT "Getting zones" +ZONES=$(GET "/zones") +ZONE_ID="null" i=0 while true; do - json="$(echo "$zones" | jq ".[$i]")" - if [ "$json" == "null" ]; then - break - fi + ZONE_JSON=$(echo $ZONES | jq ".[$i]") + + if [ "$ZONE_JSON" == "null" ]; then + break + fi - name="$(echo "$json" | jq -r ".name")" - id="$(echo "$json" | jq -r ".id")" + NAME=$(echo $ZONE_JSON | jq -r ".name") + ID=$(echo $ZONE_JSON | jq -r ".id") - log "found zone: $name ($id)" + LOG "Found zone $NAME ($ID)" + + if [ "$NAME" == "$ZONE" ]; then + ZONE_ID=$ID + break + fi - if [ "$name" == "$zone" ]; then - zone_id="$id" - break - fi + ((i=i+1)) - ((i=i+1)) done -if [ "$zone_id" == "null" ]; then - error "could not find zone: $zone" - die -fi +if [ "$ZONE_ID" == "null" ]; then + ERROR "Could not find zone $DOMAIN" + exit 1 +fi + +EVENT "Getting records" -# Step 2: get the current record id if it exists -step "fetching records..." +RECORDS=$(GET "/zones/$ZONE_ID/dns_records") -records="$(get "/zones/$zone_id/dns_records")" -current="null" +IPv4Current="null" +IPv6Current="null" +IPv4Id="null" +IPv6Id="null" i=0 while true; do + + RECORD=$(echo $RECORDS | jq ".[$i]") - _record="$(echo "$records" | jq ".[$i]")" + if [ "$RECORD" == "null" ]; then + break + fi - if [ "$_record" == "null" ]; then - break - fi + NAME=$(echo $RECORD | jq -r '.name') + TYPE=$(echo $RECORD | jq -r '.type') + CONTENT=$(echo $RECORD | jq -r '.content') + ID=$(echo $RECORD | jq -r '.id') - name="$(echo "$_record" | jq -r ".name")" - type="$(echo "$_record" | jq -r ".type")" - _content="$(echo "$_record" | jq -r ".name")" - id="$(echo "$_record" | jq -r ".id")" + LOG "Found record $NAME $TYPE \"$CONTENT\" ($ID)" - log "found record: $name $type \"$_content\" ($id)" + if [ "$NAME" == "$DOMAIN" ] && [ "$TYPE" == "A" ]; then + IPv4Current="$CONTENT" + IPv4Id="$ID" + fi - if [ "$name" == "$domain" ] && [ "$record" = "$type" ]; then - current="$id" - break - fi + if [ "$NAME" == "$DOMAIN" ] && [ "$TYPE" == "AAAA" ]; then + IPv6Current="$CONTENT" + IPv6Id="$ID" + fi + + ((i=i+1)) - ((i=i+1)) done -# Step 3: update record -step "updating record" +EVENT "Getting current IPs" + +IPv4New=$(curl ip.me -4sL --silent) +LOG "Using IPv4 $IPv4New" + +IPv6New=$(curl ip.me -6sL --silent) +LOG "Using IPv6 $IPv6New" -update() { - patch "/zones/$zone_id/dns_records/$1" "$2" +UPDATE() { + PATCH "/zones/$ZONE_ID/dns_records/$1" "$2" > /dev/null } -create() { - post "/zones/$zone_id/dns_records" "$1" +CREATE() { + POST "/zones/$ZONE_ID/dns_records" "$1" > /dev/null } -json="{ - \"name\": \"$domain\", - \"proxied\": false, - \"type\": \"$record\", - $content +IPv4JSON="{ + \"content\": \"$IPv4New\", + \"name\": \"$DOMAIN\", + \"proxied\": false, + \"type\": \"A\" +}" + +IPv6JSON="{ + \"content\": \"$IPv6New\", + \"name\": \"$DOMAIN\", + \"proxied\": false, + \"type\": \"AAAA\" }" -log $(echo "$json" | jq -C) +EVENT "Updating records" -if [ "$current" == "null" ]; then - log "no record found... creating new one" - create "$json" +if [ "$IPv4Id" == "null" ]; then + LOG "No IPv4 record found... creating new one" + CREATE "$IPv4JSON" +elif [ "$IPv4Current" != "$IPv4New" ]; then + LOG "IPv4 record found... updating" + UPDATE "$IPv4Id" "$IPv4JSON" else - log "record found... updating" - update "$current" "$json" + LOG "IPv4 is up to date... skipping" fi -step "successfully updated record" +if [ -z "$IPv6New" ]; then + LOG "System does not support IPv6... skipping" +elif [ "$IPv6Id" == "null" ]; then + LOG "No IPv6 record found... creating new one" + CREATE "$IPv6JSON" +elif [ "$IPv6Current" != "$IPv6New" ]; then + LOG "IPv6 record found... updating" + UPDATE "$IPv6Id" "$IPv6JSON" +else + LOG "IPv6 is up to date... skipping" +fi + +EVENT "Successfully updated records" + |