Skip to content

Commit

Permalink
Refactored logic. Fixed for #2.
Browse files Browse the repository at this point in the history
  • Loading branch information
parthpower committed Jan 1, 2019
1 parent 4af8757 commit c915d33
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 53 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ I have no idea but it should work.

## Notes

- To save number of API calls this script updates the `A` record only when the host IP changes. It does not periodically check if the record is modified by other means. You can use `--always-update-dns` to update the record entry at the interval.

- What is DNS record? https://www.cloudflare.com/learning/dns/dns-records/ (Psst: We are just messing with `A` record here)

- Works on CloudFlare API `v4`
Expand Down
118 changes: 65 additions & 53 deletions cf_ddns.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# Load Default Config
interval=10
save=false
always_update_dns=false
. ./config.ini
while (( "$#" )); do
case "$1" in
Expand Down Expand Up @@ -34,15 +35,21 @@ while (( "$#" )); do
save=true
shift
;;
--always-update-dns)
always_update_dns=true
shift
;;
-h|--help)
printf "Usage: ./cf_ddns.sh \t[-z|--zone <zone id>
-e|--email <email>
-k|--key <API key>]
[-c|--config <config file to load/store>]
[-s|--save]
[--always-update-dns]
[-i|--interval <update interval in seconds>]
[sub.primary.com]
Use --alway-update-dns will match DNS record with the machine IP at every interval. Not recommended for free tier DNS.
Example:
To host current ip at test.example.com
./cf_ddns.sh --key <api key> --zone <zone id> --email <your email> --interval 60 --config config.ini --save test.example.com
Expand All @@ -64,12 +71,12 @@ done

if [[ $config_file ]]; then
if [[ $save ]]; then
echo "Saving config..."
echo "zone=$zone;" > $config_file
echo "key=$key;" >> $config_file
echo "email=$email;" >> $config_file
echo "name=$name;" >> $config_file
echo "interval=$interval;" >> $config_file
echo "Saving config...";
echo "zone=$zone;" > $config_file;
echo "key=$key;" >> $config_file;
echo "email=$email;" >> $config_file;
echo "name=$name;" >> $config_file;
echo "interval=$interval;" >> $config_file;
else
. $config_file
fi
Expand All @@ -79,76 +86,81 @@ fi
printf "[config] Zone:\t$zone
[config] Key:\t************
[config] Email:\t$email
[config] Name:\t$name\n"
[config] Name:\t$name\n";

# Main Code
###############
endpoint="https://api.cloudflare.com/client/v4/zones/$zone/dns_records";
headers="-H Content-type:application/json -H X-Auth-Key:$key -H X-Auth-Email:$email";

# Get Current IP Address and try to find records similar to it
echo "[$(date)] INFO: Getting IP"
ip=$(curl -s http://api.ipify.org||echo 'null');
last_ip=$ip;

echo "[$(date)] INFO: Current IP:$last_ip"
echo "[$(date)] INFO: Fetchin Record"

content=$(curl -s -X GET $headers $endpoint\?content=$ip\&name=$name||echo 'null');
id=$(echo $content|jq -r '.result[0].id') # it will be 'null' if not found. Checked in main loop.
sucess=$(echo $content|jq -r '.result[0].sucess')

# Make sure internet is working to start up
while [[ $last_ip = 'null' || sucess = 'false' ]]; do
last_ip=$(curl -s http://api.ipify.org||echo 'null')
content=$(curl -s -X GET $headers $endpoint\?content=$ip\&name=$name||echo 'null');
id=$(echo $content|jq -r '.result[0].id');
name=$(echo $content|jq -r '.result[0].name');
sucess=$(echo $content|jq -r '.result[0].sucess');
# We are offline
echo "[$(date)] WARNING: Offline. Waiting for $interval s."
sleep $interval
continue
done

a_name=$(echo $name|cut -d'.' -f1)
id="null";
last_ip="null";

while [[ true ]]; do
# Update IP
current_ip=$(curl -s http://api.ipify.org||echo 'null')
echo "[$(date)] INFO: Current IP:$ip";

# Check if offline
if [[ $current_ip = 'null' ]]; then

echo "[$(date)] WARNING: You are offline"
echo "[$(date)] WARNING: Failed to get your IP.";
sleep $interval
continue
else
echo "[$(date)] INFO: Current IP:$current_ip";
fi

# Check for IP Updates or if it requires creating new record.
if [[ $current_ip = $last_ip && $id != 'null' ]]; then

echo "[$(date)] INFO: No updates"
sleep $interval
continue
if [[ $always_update_dns = 'false' ]] ; then
# Skip to start if there is no updates in IP
if [[ $current_ip = $last_ip ]]; then
echo "[$(date)] INFO: Host IP Unchanged. Not checking DNS Records.";
sleep $interval;
continue;
else
last_ip=$current_ip;
fi
fi

# Code gets here only if IP is updated or to create new record
last_ip=$current_ip;
ip=$current_ip;

# Check if DNS Record Exist
echo "[$(date)] INFO: Checking for existing DNS Record.";
content=$(curl -s -X GET $headers $endpoint\?\&name=$name||echo 'null');
id=$(echo $content|jq -r '.result[0].id');
ip_on_record=$(echo $content|jq -r '.result[0].content');
echo "[$(date)] INFO: DNS Record ID:$id";
echo "[$(date)] INFO: IP on DNS Record $ip_on_record";

if [[ $id = 'null' ]] ; then
# Create Record
echo "[$(date)] INFO: Creating New Record"
content=$(curl -s -X POST $headers $endpoint/$id -d "{\"type\":\"A\",\"name\":\"$a_name\",\"content\":\"$ip\",\"proxied\":false}");
content=$(curl -s -X POST $headers $endpoint -d "{\"type\":\"A\",\"name\":\"$a_name\",\"content\":\"$current_ip\",\"proxied\":false}");
id=$(echo $content|jq -r '.result.id');

echo "[$(date)] INFO: $content";
echo "[$(date)] INFO: Record ID:$id";

if [[ $(echo $content | jq -r '.success') != 'true' ]]; then
echo "[$(date)] ERROR: Failed with errors $(echo $content | jq -r '.errors')";
continue;
fi
else
echo "[$(date)] INFO: Updating Record"
content=$(curl -s -X PUT $headers $endpoint -d "{\"type\":\"A\",\"name\":\"$a_name\",\"content\":\"$ip\",\"proxied\":false}");
if [[ $ip_on_record != $current_ip ]]; then
# Update Existing DNS Record
echo "[$(date)] INFO: Updating Existing Record ID: $id";
content=$(curl -s -X PUT $headers $endpoint/$id -d "{\"type\":\"A\",\"name\":\"$a_name\",\"content\":\"$current_ip\",\"proxied\":false}");
id=$(echo $content|jq -r '.result.id');

echo "[$(date)] INFO: $content";
echo "[$(date)] INFO: Record ID:$id";

if [[ $(echo $content | jq -r '.success') != 'true' ]]; then
echo "[$(date)] ERROR: Failed with errors $(echo $content | jq -r '.errors')";
continue;
fi

else
echo "[$(date)] INFO: Not updating A record because IP on record is same as host ip.";
fi
fi
id=$(echo $content|jq -r '.result.id');
echo "[$(date)] INFO: $content";
echo "[$(date)] INFO: Record ID:$id";

sleep $interval
done

0 comments on commit c915d33

Please sign in to comment.