Created
March 5, 2023 13:26
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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