Skip to content

Instantly share code, notes, and snippets.

@pboos
Last active December 10, 2015 13:49
Show Gist options
  • Save pboos/4443466 to your computer and use it in GitHub Desktop.
Save pboos/4443466 to your computer and use it in GitHub Desktop.
Script to update dns on Route 53. Original script by Johan Lindh with some changes to allow root A record update with "" for hostname.
#!/bin/sh
# This script will perform a DynDNS-like function for Amazon's Route 53
#
# Author: Johan Lindh <[email protected]>
# http://www.linkdata.se/
#
# Script requirements:
#
# wget
# grep
# sed
# dig
# cut
# openssl
# base64
#
# Most if not all of these come standard on *nix distros.
#
if [ "$#" != "5" ]; then
echo "Usage: dnsupdate.sh <awsid> <awskey> <zoneid> <hostname> <domain>"
echo "Sample: dnsupdate.sh 12345678901234 m29a39sk349a/as03/asdf Z0000000000 home domain.com"
exit 1
fi
# The domain and host name to update
# and the desired TTL of the record
Domain=$5
Hostname=$4
NewTTL=600
# The Amazon Route 53 zone ID for the domain
# and the Amazon ID and SecretKey. Remember to
# ensure that this file can't be read by
# unauthorized people!
ZoneID=$3
AmazonID=$1
SecretKey=$2
# Enter the URL used to check extern IP
CheckIPURL='http://checkip.dyndns.com/'
# Enter some static text that immediately preceeds the current IP in the HTML output
# Note that you'll probably need to look at the actual HTML code to find this
CheckIPText='Current IP Address:'
###############################################################
# You should not need to change anything beyond this point
###############################################################
DNSFullName="$Hostname.$Domain"
DNSFullNameForGrep="$Hostname\.$Domain"
if [ "$Hostname" = "" ]; then
DNSFullName="$Domain"
DNSFullNameForGrep="$Domain"
fi
# Retrieve the current IP
CurrentIP=$(wget "$CheckIPURL" -o /dev/null -O /dev/stdout | grep "$CheckIPText" | sed 's/.*[^0-9]\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\)[^0-9].*/\1/')
# Find an authoritative AWS R53 nameserver so we get a clean TTL
AuthServer=$(dig NS $Domain | grep -v ';' | grep -m 1 awsdns | grep $Domain | cut -f 6)
if [ "$AuthServer" = "NS"]; then
# For short domains like pes.ch it is cut-f 7
AuthServer=$(dig NS $Domain | grep -v ';' | grep -m 1 awsdns | grep $Domain | cut -f 7)
fi
if [ "$AuthServer" = "" ]; then
echo The domain $Domain has no authoritative Amazon Route 53 name servers
exit 1
fi
# Get the record and extract its parts
Record=$(dig @$AuthServer A $DNSFullName | grep -v ";" | grep "$DNSFullNameForGrep")
OldType=$( echo $Record | cut -d ' ' -f 4 )
OldTTL=$( echo $Record | cut -d ' ' -f 2 )
OldIP=$( echo $Record | cut -d ' ' -f 5 )
# Make sure it is an A record (could be CNAME)
if [ "$Record" != "" -a "$OldType" != "A" ]; then
echo $DNSFullName has a $OldType record, expected 'A'
exit 1
fi
# Changeset preamble
Changeset=""
Changeset=$Changeset"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
Changeset=$Changeset"<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2010-10-01/\">"
Changeset=$Changeset"<ChangeBatch><Comment>Update $DNSFullName</Comment><Changes>"
if [ "$OldIP" != "" ]; then
# Add a DELETE request to the changeset
Changeset=$Changeset"<Change>"
Changeset=$Changeset"<Action>DELETE</Action>"
Changeset=$Changeset"<ResourceRecordSet>"
Changeset=$Changeset"<Name>$DNSFullName.</Name>"
Changeset=$Changeset"<Type>A</Type>"
Changeset=$Changeset"<TTL>$OldTTL</TTL>"
Changeset=$Changeset"<ResourceRecords>"
Changeset=$Changeset"<ResourceRecord>"
Changeset=$Changeset"<Value>$OldIP</Value>"
Changeset=$Changeset"</ResourceRecord>"
Changeset=$Changeset"</ResourceRecords>"
Changeset=$Changeset"</ResourceRecordSet>"
Changeset=$Changeset"</Change>"
fi
# Add CREATE request to the changeset
Changeset=$Changeset"<Change>"
Changeset=$Changeset"<Action>CREATE</Action>"
Changeset=$Changeset"<ResourceRecordSet>"
Changeset=$Changeset"<Name>$DNSFullName.</Name>"
Changeset=$Changeset"<Type>A</Type>"
Changeset=$Changeset"<TTL>$NewTTL</TTL>"
Changeset=$Changeset"<ResourceRecords>"
Changeset=$Changeset"<ResourceRecord>"
Changeset=$Changeset"<Value>$CurrentIP</Value>"
Changeset=$Changeset"</ResourceRecord>"
Changeset=$Changeset"</ResourceRecords>"
Changeset=$Changeset"</ResourceRecordSet>"
Changeset=$Changeset"</Change>"
# Close the changeset
Changeset=$Changeset"</Changes>"
Changeset=$Changeset"</ChangeBatch>"
Changeset=$Changeset"</ChangeResourceRecordSetsRequest>"
if [ "$OldIP" != "$CurrentIP" ]; then
# Get the date at the Amazon servers
CurrentDate=$(wget -q -S https://route53.amazonaws.com/date -O /dev/null 2>&1 | grep Date | sed 's/.*Date: //')
# Calculate the SHA1 hash and required headers
Signature=$(echo -n $CurrentDate | openssl dgst -binary -sha1 -hmac $SecretKey | base64)
DateHeader="Date: "$CurrentDate
AuthHeader="X-Amzn-Authorization: AWS3-HTTPS AWSAccessKeyId=$AmazonID,Algorithm=HmacSHA1,Signature=$Signature"
# Submit request
Result=$(wget -nv --header="$DateHeader" --header="$AuthHeader" --header="Content-Type: text/xml; charset=UTF-8" --post-data="$Changeset" -O /dev/stdout -o /dev/stdout https://route53.amazonaws.com/2010-10-01/hostedzone/$ZoneID/rrset)
if [ "$?" -ne "0" ]; then
echo "Failed to update $DNSFullName: "$Result
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment