diff --git a/cfddnsv6.sh b/cfddnsv6.sh new file mode 100644 index 0000000..d295b56 --- /dev/null +++ b/cfddnsv6.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# AUTHOR: Josh North +# EMAIL: josh.north@point808.com +# BRIEF: This script updates CloudFlare IPv6 DNS records with your current IP +# address, as pulled from the interface directly. Best use case is having an +# ISP who arbitrarily changes your prefix. For safety, we do not create +# records, we only update records that match the hostname in the zone, so +# you must log in to CloudFlare and create your records first! +# USAGE: Put this file in /usr/local/bin/cfddnsv6.sh or wherever you prefer is ok. +# Make sure to chmod +x and make it executable. Change the settings below to +# Match your login and environment needs. Run it from command line to test. +# Right now we run this from cron--- at reboot and every so often after. +# This example runs it at reboot and every half hour, adjust to taste +# @reboot /usr/local/bin/cfddnsv6.sh >/dev/null 2>&1 +# */30 * * * * /usr/local/bin/cfddnsv6.sh >/dev/null 2>&1 + +# SETTINGS: +CF_EMAIL="you@zone.com" # Email address you use to log in to CloudFlare. +CF_KEY="YourApiKeyHere" # API key for CloudFlare account (get from Account Settings page). +CF_ZONE="zone.com" # MUST match zone you want to update host in! +CF_HOST="webserver" # Hostname of record. Create in CloudFlare first! +CF_IF="eth0" # What interface should we get the IP address for? +CF_LOG="/var/log/cfddnsv6.log" # Where to log actions taken by this script. + +# -------------------- NOTHING TO CHANGE BELOW THIS LINE -------------------- +# CloudFlare API URI +CF_URL="https://api.cloudflare.com/client/v4" +CF_AUTH=(-H "X-Auth-Email: $CF_EMAIL" -H "X-Auth-Key: $CF_KEY" -H "Content-Type: application/json") +CURLCMD="curl -sS -X" + +# Make sure we have all needed programs +command -v curl >/dev/null 2>&1 || { echo "This script requires curl but I cannot find it on this system... Exiting now." >&2; exit 1; } + +# Log start of script +printf "%s\n" "$(date) Beginning DNS update process" >> $CF_LOG + +# This is a pause to wait for tentative addresses to disappear. You may comment this out if you have reason to do so, I include it because in my networks, these addresses go away. +while ip -6 addr show tentative | grep . > /dev/null ; do sleep 1 ; done + +# Try to get the best global address from the chosen interface +CF_IPV6=$(ip addr show dev $CF_IF | grep -Ev "deprecated" | sed -e's/^.*inet6 \([^ ]*\)\/.*$/\1/;t;d' | grep -Ev "^fd|^fe80" | sed -n '$p') + +# Look up CloudFlare zone identifier +CF_ZONE_ID=$($CURLCMD GET "$CF_URL/zones?name=$CF_ZONE" "${CF_AUTH[@]}" | cut -d '"' -f6) + +# Get record identifier from CloudFlare +CF_RECORD_ID=$($CURLCMD GET "$CF_URL/zones/$CF_ZONE_ID/dns_records?type=AAAA&name=$CF_HOST.$CF_ZONE" "${CF_AUTH[@]}" | cut -d '"' -f6) + +# Log what we are going to try +printf "%s\n" "$(date) IP on $CF_IF is $CF_IPV6" >> $CF_LOG +printf "%s\n" "$(date) Record to update is $CF_HOST.$CF_ZONE ($CF_RECORD_ID)" >> $CF_LOG + +# Build the request string and submit +CF_REQUEST=$($CURLCMD PUT "$CF_URL/zones/$CF_ZONE_ID/dns_records/$CF_RECORD_ID" "${CF_AUTH[@]}" \ + --data "{\"id\":\"$CF_RECORD_ID\",\"type\":\"AAAA\",\"name\":\"$CF_HOST\",\"content\":\"$CF_IPV6\",\"zone_id\":\"$CF_ZONE_ID\",\"zone_name\":\"$CF_ZONE\",\"data\":{}}" | sed -n -e 's/^.*\("success":\)/\1/p') + +# Log output +printf "%s\n" "$(date) Result string is $CF_REQUEST" >> $CF_LOG + +# All done +exit 0 +# EOF