Skip to content

Instantly share code, notes, and snippets.

@kernelkaribou
Created March 5, 2023 13:26
Show Gist options
  • Save kernelkaribou/39e4f0d784d7ad8cbd0dc740dbc6ae7d to your computer and use it in GitHub Desktop.
Save kernelkaribou/39e4f0d784d7ad8cbd0dc740dbc6ae7d to your computer and use it in GitHub Desktop.
Simple bash script to update Cloudflare DNS record to represent local public IP i.e. DDNS script
#!/bin/bash
####################################################################################
# Author: Kernelkaribou@github
#
# Purpose: Update a DNS record hosted at Cloudflare to represent network public IP.
# Based upon Cloudflare API v4
#
# In cloudflare, create API key for your zone in question, e.g. example.com
# Ensuring that it has Zone Read and DNS Edit permissions. DO NOT use a Global Key
# for your account as that is unnecessarily permissive.
#
# Fill in the below user defined variables and set up a cron to run on a necessary interval
# e.g. every hour, 5 minutes, day, etc.
#
# When ran manually it will output results to the screen but will also write to syslog
# for unattended runs and historic review.
#
# Last Update: 03/05/2023
####################################################################################
### User Defined
#Main domain zone e.g. example.com
ZONE_DOMAIN="EXAMPLE.COM"
#DNS Record to update e.g. home.example.com
DNS_RECORD="RECORD.EXAMPLE.COM"
#API Key generated with Zone Read and DNS Edit permissions on above Main Zone, NOT A GLOBAL KEY!
API_KEY="CLOUDFLAREAPIKEY"
#Send message of execution to log center on Synology
writeLog()
{
echo $2
logger "Cloudflare DDNS: ${2}"
}
### Main Script
#Get my public IP address
PUBLIC_IP=$(curl -s ifconfig.me)
#Get current DNS Record configured IP from Cloudflare
CURRENT_DNS_IP=$(nslookup -type=a $DNS_RECORD 1.1.1.1 | grep 'Address' | awk -F":" 'NF==2' | awk '{ if($2 !~ /#/){print $2}}')
#CHECK IF DNS Record matches Public IP
if [[ $CURRENT_DNS_IP == $PUBLIC_IP ]]; then
#IP Matches no need to continue
MESSAGE="$DNS_RECORD IP: $CURRENT_DNS_IP, Public IP: $PUBLIC_IP Match! No DNS update necessary!"
MESSAGE_TYPE="info"
writeLog "$MESSAGE_TYPE" "$MESSAGE"
else
MESSAGE="$DNS_RECORD IP $CURRENT_DNS_IP, Public IP: $PUBLIC_IP Mismatch! Updating!"
MESSAGE_TYPE="info"
writeLog "$MESSAGE_TYPE" "$MESSAGE"
#Getting Domain Zone ID
ZONE_RESULT=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$ZONE_DOMAIN" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json")
ZONE_ID=$(echo $ZONE_RESULT | grep -oP "(?<={\"result\":\[{\"id\":\").*?(?=\",)")
echo "ZONE ID: $ZONE_ID"
if [ -z "$ZONE_ID" ]; then
MESSAGE="Unable to get ID for Zone '$ZONE_DOMAIN', check script configuration and API key"
MESSAGE_TYPE="err"
writeLog "$MESSAGE_TYPE" "$MESSAGE"
echo $ZONE_RESULT
exit 1
fi
#Getting DNS Record ID
RECORD_RESULT=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?name=$DNS_RECORD" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json")
DNS_ID=$(echo $RECORD_RESULT | grep -oP "(?<={\"result\":\[{\"id\":\").*?(?=\",)")
echo "DNS RECORD ID: $DNS_ID"
if [ -z "$DNS_ID" ]; then
MESSAGE="Unable to get ID for DNS Record '$DNS_RECORD', check script configuration and Zone ID"
MESSAGE_TYPE="err"
writeLog "$MESSAGE_TYPE" "$MESSAGE"
echo $RECORD_RESULT
exit 1
fi
#Updating DNS record.
RESPONSE=$(curl -s -X PUT https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$DNS_ID \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-H "cache-control: no-cache" \
-d "{\"type\" : \"A\", \"name\" : \"$DNS_RECORD\", \"content\" : \"$PUBLIC_IP\" }")
#Update failed
ERROR_STRING='"success":false,'
if [[ "$RESPONSE" == *"$ERROR_STRING"* ]]; then
ERROR_MESSAGE=""
if [[ $RESPONSE =~ \"errors\"\:[{.*[A-Za-z0-9].*}\] ]]; then
ERROR_MESSAGE=$(echo ${BASH_REMATCH[0]} | sed 's/[^a-z A-Z:0-9]/ /g')
else
ERROR_MESSAGE="Unable to parse error message"
fi
MESSAGE="DNS Record $DNS_RECORD error on update: $PUBLIC_IP - $ERROR_MESSAGE"
MESSAGE_TYPE="err"
#Update was successful
else
MESSAGE="DNS Record $DNS_RECORD successfully updated to $PUBLIC_IP"
MESSAGE_TYPE="info"
NOTIFICATION="$DNS_RECORD was successfully updated to $PUBLIC_IP"
fi
writeLog "$MESSAGE_TYPE" "$MESSAGE"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment