Skip to content

Instantly share code, notes, and snippets.

@venator85
Created January 26, 2017 22:05
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save venator85/0b677e535dd35e2cd02c54ed445221ed to your computer and use it in GitHub Desktop.
Save venator85/0b677e535dd35e2cd02c54ed445221ed to your computer and use it in GitHub Desktop.
Custom AsusWRT DDNS script for AWS Route53
#!/bin/sh
# note: when debugging on PC/MAC, this script must be run with bash
# Custom AsusWRT DDNS script for AWS Route53 - v1.0
# Author: Alessio Bianchi <me@alessiobianchi.eu>
# Credits: http://czak.pl/2015/09/15/s3-rest-api-with-curl.html
ACCESS_KEY_ID="XXXXXXXXXXXXXXXXXXXX"
SECRET_ACCESS_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# These keys can be associated to a IAM user with the following policy:
# {
# "Version": "2012-10-17",
# "Statement": [
# {
# "Sid": "Stmt1440351730000",
# "Effect": "Allow",
# "Action": [
# "route53:ChangeResourceRecordSets",
# "route53:GetHostedZone",
# "route53:ListHostedZones",
# "route53:ListResourceRecordSets"
# ],
# "Resource": [
# "*"
# ]
# }
# ]
# }
REGION="us-east-1" # fixed for route53
SERVICE="route53"
API_HOST="route53.amazonaws.com"
HOSTED_ZONE_ID="ZXXXXXXXXXXXX"
NAME="my.domain.com."
RESOURCE_TYPE="A"
TTL=300
MAILGUN_API_KEY="key-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
MAILGUN_DOMAIN="domain.com"
MAILGUN_FROM_ADDRESS="me@domain.com"
MAILGUN_TO_ADDRESS="recipient@example.com"
# ----
IFS=
DATE=$(date -u +"%Y%m%dT%H%M%SZ")
DATE_SHORT=$(date -u +"%Y%m%d")
OPENSSL="openssl"
SED="sed"
os=$(uname)
if [ "$os" == "Darwin" ]; then # for debugging on macOS
OPENSSL="/usr/local/Cellar/openssl/1.0.2j/bin/openssl" # from HomeBrew: brew install openssl
SED="gsed" # from HomeBrew: brew install gnu-sed
fi
EXTERNAL_IP="$1"
sha256() {
data="$1"
echo -n "${data}" | ${OPENSSL} dgst -sha256 | sed 's/^.* //'
}
hmac_sha256() {
key="$1"
data="$2"
echo -n "${data}" | ${OPENSSL} dgst -sha256 -mac HMAC -macopt "${key}" | sed 's/^.* //'
}
buildSigningKey() {
service="$1"
dateKey=$(hmac_sha256 "key:AWS4${SECRET_ACCESS_KEY}" "${DATE_SHORT}")
dateRegionKey=$(hmac_sha256 "hexkey:${dateKey}" "${REGION}")
dateRegionServiceKey=$(hmac_sha256 "hexkey:${dateRegionKey}" "${service}")
hmac_sha256 "hexkey:${dateRegionServiceKey}" "aws4_request"
}
buildCreq() {
HTTPMethod="$1"
CanonicalURI="$2"
CanonicalQueryString="$3"
CanonicalHeaders="$4"
SignedHeaders="$5"
Payload="$6"
hashedPayload=$(sha256 "${Payload}")
printf "%s\n%s\n%s\n%s\n\n%s\n%s" "${HTTPMethod}" "${CanonicalURI}" "${CanonicalQueryString}" "${CanonicalHeaders}" "${SignedHeaders}" "${hashedPayload}"
}
buildSts() {
creq="$1"
scope="$2"
CanonicalRequestHash=$(sha256 "${creq}")
printf "AWS4-HMAC-SHA256\n%s\n%s\n%s" "${DATE}" "${scope}" "${CanonicalRequestHash}"
}
signSts() {
sts="$1"
signingKey="$2"
hmac_sha256 "hexkey:${signingKey}" "${sts}"
}
bodyTemplate='<ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/2013-04-01/"><ChangeBatch><Changes><Change><Action>UPSERT</Action><ResourceRecordSet><Name>%s</Name><Type>%s</Type><TTL>%d</TTL><ResourceRecords><ResourceRecord><Value>%s</Value></ResourceRecord></ResourceRecords></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>'
body=$(printf "${bodyTemplate}" "${NAME}" "${RESOURCE_TYPE}" "${TTL}" "${EXTERNAL_IP}")
canonicalHeaders=$(printf 'host:%s\nx-amz-date:%s' "${API_HOST}" "${DATE}")
signedHeaders="host;x-amz-date"
req="/2013-04-01/hostedzone/${HOSTED_ZONE_ID}/rrset"
creq=$(buildCreq "POST" "${req}" "" "${canonicalHeaders}" "${signedHeaders}" "${body}")
#echo -e "creq:\n${creq}\n"
scope="${DATE_SHORT}/${REGION}/${SERVICE}/aws4_request"
sts=$(buildSts "${creq}" "${scope}")
#echo -e "sts:\n${sts}\n"
signingKey=$(buildSigningKey ${SERVICE})
#echo -e "signingKey:\n${signingKey}\n"
signature=$(signSts "${sts}" "${signingKey}")
#echo -e "signature:\n${signature}\n"
authorizationHeader=$(printf "Authorization: AWS4-HMAC-SHA256 Credential=%s/%s, SignedHeaders=%s, Signature=%s" "${ACCESS_KEY_ID}" "${scope}" "${signedHeaders}" "${signature}")
#echo -e "authorizationHeader:\n${authorizationHeader}\n"
req_output=$(curl -i "https://${API_HOST}${req}" -d "${body}" -H "${authorizationHeader}" -H "x-amz-date: ${DATE}" -H "Content-Type: application/xml" 2>&1)
status_code=$(echo ${req_output} | grep 'HTTP/1.1' | ${SED} -r 's/.*? ([0-9]+) .*?/\1/g')
if [ ${status_code} -ne 200 ]; then
mailMsg=$(printf "There was an error updating %s to IP address %s.\n\n%s" "${NAME}" "${EXTERNAL_IP}" "${req_output}")
curl -i --user "api:${MAILGUN_API_KEY}" \
https://api.mailgun.net/v3/${MAILGUN_DOMAIN}/messages \
-F from="AsusWRT Route53 DDNS <${MAILGUN_FROM_ADDRESS}>" \
-F to="${MAILGUN_TO_ADDRESS}" \
-F subject="[${NAME}] Route53 DDNS update failure" \
-F text="${mailMsg}" 2>&1 | logger
/sbin/ddns_custom_updated 0
else
/sbin/ddns_custom_updated 1
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment