cloudflare-autodns/dns.sh
2023-09-12 09:05:20 -04:00

170 lines
3.2 KiB
Bash
Executable file

#!/usr/bin/env sh
API_TOKEN="${API_TOKEN:-ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcd}"
ZONE="${ZONE:-example.com}"
DOMAIN="${DOMAIN:-example.com}"
EVENT() {
printf "\x1b[95m>>> \x1b[0m\x1b[98m$1\n"
}
LOG() {
printf "\x1b[98m$1\n"
}
ERROR() {
>&2 printf "\x1b[91mError: \x1b[0m\x1b[98m$1\n"
}
CURL() {
RESPONSE=$(curl --silent --request $1 \
--url "https://api.cloudflare.com/client/v4$2" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer $API_TOKEN" \
--data "$3")
SUCCESS=$(echo $RESPONSE | jq -r ".success")
if [ "$SUCCESS" != "true" ]; then
ERROR "$(echo $RESPONSE | jq -r ".errors[0].message")"
kill $$
fi
echo $RESPONSE | jq ".result"
}
PATCH() {
CURL "PATCH" "$1" "$2"
}
POST() {
CURL "POST" "$1" "$2"
}
GET() {
CURL "GET" "$1" ""
}
EVENT "Getting zones"
ZONES=$(GET "/zones")
ZONE_ID="null"
i=0
while true; do
ZONE_JSON=$(echo $ZONES | jq ".[$i]")
if [ "$ZONE_JSON" == "null" ]; then
break
fi
NAME=$(echo $ZONE_JSON | jq -r ".name")
ID=$(echo $ZONE_JSON | jq -r ".id")
LOG "Found zone $NAME ($ID)"
if [ "$NAME" == "$ZONE" ]; then
ZONE_ID=$ID
break
fi
((i=i+1))
done
if [ "$ZONE_ID" == "null" ]; then
ERROR "Could not find zone $DOMAIN"
exit 1
fi
EVENT "Getting records"
RECORDS=$(GET "/zones/$ZONE_ID/dns_records")
IPv4Current="null"
IPv6Current="null"
IPv4Id="null"
IPv6Id="null"
i=0
while true; do
RECORD=$(echo $RECORDS | jq ".[$i]")
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')
LOG "Found record $NAME $TYPE \"$CONTENT\" ($ID)"
if [ "$NAME" == "$DOMAIN" ] && [ "$TYPE" == "A" ]; then
IPv4Current="$CONTENT"
IPv4Id="$ID"
fi
if [ "$NAME" == "$DOMAIN" ] && [ "$TYPE" == "AAAA" ]; then
IPv6Current="$CONTENT"
IPv6Id="$ID"
fi
((i=i+1))
done
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" > /dev/null
}
CREATE() {
POST "/zones/$ZONE_ID/dns_records" "$1" > /dev/null
}
IPv4JSON="{
\"content\": \"$IPv4New\",
\"name\": \"$DOMAIN\",
\"proxied\": false,
\"type\": \"A\"
}"
IPv6JSON="{
\"content\": \"$IPv6New\",
\"name\": \"$DOMAIN\",
\"proxied\": false,
\"type\": \"AAAA\"
}"
EVENT "Updating records"
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 "IPv4 is up to date... skipping"
fi
if [ "$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"