ddns-scripts: Support Amazon AWS Route53 as a ddns provider 5319/head
authorMax Berger <max@berger.name>
Sat, 23 Dec 2017 21:47:48 +0000 (22:47 +0100)
committerMax Berger <max@berger.name>
Tue, 9 Jan 2018 21:08:51 +0000 (22:08 +0100)
Based on a sh-only route53 update script by Yuval Adam
https://github.com/yuvadm/route53-ddns/blob/master/route53.sh

Signed-off-by: Max Berger <max@berger.name>
net/ddns-scripts/Makefile
net/ddns-scripts/files/services
net/ddns-scripts/files/services_ipv6
net/ddns-scripts/files/update_route53_v1.sh [new file with mode: 0644]

index d4023c01fa88bd8ffe3d5b9196c10462af1f3c96..fbc716e8f2b0dda82a1866f2efc9910a4d32a6e5 100755 (executable)
@@ -9,10 +9,10 @@ include $(TOPDIR)/rules.mk
 PKG_NAME:=ddns-scripts
 # Version == major.minor.patch
 # increase on new functionality (minor) or patches (patch)
-PKG_VERSION:=2.7.6
+PKG_VERSION:=2.7.7
 # Release == build
 # increase on changes of services files or tld_names.dat
-PKG_RELEASE:=21
+PKG_RELEASE:=1
 
 PKG_LICENSE:=GPL-2.0
 PKG_MAINTAINER:=Christian Schoenebeck <christian.schoenebeck@gmail.com>
@@ -112,6 +112,21 @@ define Package/ddns-scripts_nsupdate/config
 
 endef
 
+###### *************************************************************************
+define Package/ddns-scripts_route53-v1
+    $(call Package/ddns-scripts/Default)
+    TITLE:=Amazon AWS Route 53 API v1
+    DEPENDS:=ddns-scripts +curl +openssl-util
+endef
+define Package/ddns-scripts_route53-v1/description
+       Dynamic DNS Client scripts extension for Amazon AWS Route53. Note: You
+       must also install ca-certificate or ca-bundle.
+       It requires:
+       "option username" to be a valid AWS access key id
+       "option password" to be the matching AWS secret key id
+       "option domain" to contain the hosted zone ID
+endef
+
 ###### *************************************************************************
 define Build/Configure
 endef
@@ -387,6 +402,47 @@ define Package/ddns-scripts_nsupdate/prerm
        exit 0  # suppress errors
 endef
 
+###### *************************************************************************
+define Package/ddns-scripts_route53-v1/preinst
+       #!/bin/sh
+       # if NOT run buildroot then stop service
+       [ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop >/dev/null 2>&1
+       exit 0  # suppress errors
+endef
+define Package/ddns-scripts_route53-v1/install
+       $(INSTALL_DIR) $(1)/etc/uci-defaults
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/files/ddns.defaults $(1)/etc/uci-defaults/ddns_route53-v1
+       $(INSTALL_DIR) $(1)/usr/lib/ddns
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/files/update_route53_v1.sh $(1)/usr/lib/ddns
+endef
+define Package/ddns-scripts_route53-v1/postinst
+       #!/bin/sh
+       # remove old services file entries
+       /bin/sed -i '/route53-v1/d' $${IPKG_INSTROOT}/etc/ddns/services         >/dev/null 2>&1
+       /bin/sed -i '/route53-v1/d' $${IPKG_INSTROOT}/etc/ddns/services_ipv6    >/dev/null 2>&1
+       # and create new
+       printf "%s\\t%s\\n" '"route53-v1"' '"update_route53_v1.sh"' >> $${IPKG_INSTROOT}/etc/ddns/services
+       printf "%s\\t%s\\n" '"route53-v1"' '"update_route53_v1.sh"' >> $${IPKG_INSTROOT}/etc/ddns/services_ipv6
+       # on real system restart service if enabled
+       [ -z "$${IPKG_INSTROOT}" ] && {
+               [ -x /etc/uci-defaults/ddns_route53-v1 ] && \
+                       /etc/uci-defaults/ddns_route53-v1 && \
+                               rm -f /etc/uci-defaults/route53.com-v1 >/dev/null 2>&1
+               /etc/init.d/ddns enabled \
+                       && /etc/init.d/ddns start >/dev/null 2>&1
+       }
+       exit 0  # suppress errors
+endef
+define Package/ddns-scripts_route53-v1/prerm
+       #!/bin/sh
+       # if NOT run buildroot then stop service
+       [ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop                             >/dev/null 2>&1
+       # remove services file entries
+       /bin/sed -i 'route53-v1/d' $${IPKG_INSTROOT}/etc/ddns/services          >/dev/null 2>&1
+       /bin/sed -i 'route53-v1/d' $${IPKG_INSTROOT}/etc/ddns/services_ipv6     >/dev/null 2>&1
+       exit 0  # suppress errors
+endef
+
 ###### *************************************************************************
 $(eval $(call BuildPackage,ddns-scripts))
 $(eval $(call BuildPackage,ddns-scripts_cloudflare))
@@ -394,3 +450,4 @@ $(eval $(call BuildPackage,ddns-scripts_cloudflare.com-v4))
 $(eval $(call BuildPackage,ddns-scripts_godaddy.com-v1))
 $(eval $(call BuildPackage,ddns-scripts_no-ip_com))
 $(eval $(call BuildPackage,ddns-scripts_nsupdate))
+$(eval $(call BuildPackage,ddns-scripts_route53-v1))
index c66c34b46c681ab0a193f3f6d4abd2b0bc54a247..d84dfc5ab20c793d1d0326133b2e7faf6dfecb65 100644 (file)
@@ -37,6 +37,7 @@
 #.cloudflare.com-v4    !!! Please install additional package "ddns-scripts_cloudflare.com-v4"
 #.godaddy.com-v1       !!! Please install additional package "ddns-scripts_godaddy.com-v1"
 #.no-ip.com / noip.com !!! Please install additional package "ddns-scripts_no-ip_com"
+#.route53-v1           !!! Please install additional package "ddns-scripts_route53-v1"
 
 "3322.org"             "http://[USERNAME]:[PASSWORD]@members.3322.org/dyndns/update?system=dyndns&hostname=[DOMAIN]&myip=[IP]"
 
index 3ea2974b166eac243c1d8f8cc50bddd56b046f26..1a2ffee5fef3ceca0d84d3924bbe3cc3df3acc8e 100644 (file)
@@ -37,6 +37,7 @@
 #.cloudflare.com-v4    !!! Please install additional package "ddns-scripts_cloudflare.com-v4"
 #.godaddy.com-v1       !!! Please install additional package "ddns-scripts_godaddy.com-v1"
 #.no-ip.com / noip.com !!! Please install additional package "ddns-scripts_no-ip_com"
+#.route53-v1           !!! Please install additional package "ddns-scripts_route53-v1"
 
 "afraid.org-basicauth" "http://[USERNAME]:[PASSWORD]@freedns.afraid.org/nic/update?hostname=[DOMAIN]&myip=[IP]"
 "afraid.org-keyauth"   "http://freedns.afraid.org/dynamic/update.php?[PASSWORD]&address=[IP]"
diff --git a/net/ddns-scripts/files/update_route53_v1.sh b/net/ddns-scripts/files/update_route53_v1.sh
new file mode 100644 (file)
index 0000000..6b9b029
--- /dev/null
@@ -0,0 +1,97 @@
+#!/bin/sh
+#.Distributed under the terms of the GNU General Public License (GPL) version 2.0
+#.based on Yuval Adam's route53.sh found at https://github.com/yuvadm/route53-ddns/blob/master/route53.sh
+#.2017 Max Berger <max at berger dot name>
+[ -z "$CURL_SSL" ] && write_log 14 "Amazon AWS Route53 communication require cURL with SSL support. Please install"
+[ -z "$username" ] && write_log 14 "Service section not configured correctly! Missing key as 'username'"
+[ -z "$password" ] && write_log 14 "Service section not configured correctly! Missing secret as 'password'"
+[ -z "$domain" ] && write_log 14 "Service section not configured correctly! Missing zone id as 'domain'"
+
+set -euo pipefail
+IFS=$'\n\t'
+
+ENDPOINT="route53.amazonaws.com"
+RECORD_TTL=300
+RECORD_NAME="$lookup_host".
+[ $use_ipv6 -eq 0 ] && RECORD_TYPE="A"
+[ $use_ipv6 -eq 1 ] && RECORD_TYPE="AAAA"
+RECORD_VALUE="$LOCAL_IP"
+HOSTED_ZONE_ID="$domain"
+API_PATH="/2013-04-01/hostedzone/${HOSTED_ZONE_ID}/rrset/"
+
+AWS_ACCESS_KEY_ID="$username"
+AWS_SECRET_ACCESS_KEY="$password"
+AWS_REGION='us-east-1'
+AWS_SERVICE='route53'
+
+hash() {
+    msg=$1
+    echo -en "$msg" | openssl dgst -sha256 | sed 's/^.* //'
+}
+
+sign_plain() {
+    # Sign message using a plaintext key
+    key=$1
+    msg=$2
+    echo -en "$msg" | openssl dgst -hex -sha256 -hmac "$key" | sed 's/^.* //'
+}
+
+sign() {
+    # Sign message using a hex formatted key
+    key=$1
+    msg=$2
+    echo -en "$msg" | openssl dgst -hex -sha256 -mac HMAC -macopt "hexkey:${key}" | sed 's/^.* //'
+}
+
+request_body="<?xml version=\"1.0\" encoding=\"UTF-8\"?> \
+<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"> \
+<ChangeBatch> \
+   <Changes> \
+      <Change> \
+         <Action>UPSERT</Action> \
+         <ResourceRecordSet> \
+            <Name>${RECORD_NAME}</Name> \
+            <Type>${RECORD_TYPE}</Type> \
+            <TTL>${RECORD_TTL}</TTL> \
+            <ResourceRecords> \
+               <ResourceRecord> \
+                  <Value>${RECORD_VALUE}</Value> \
+               </ResourceRecord> \
+            </ResourceRecords> \
+         </ResourceRecordSet> \
+      </Change> \
+   </Changes> \
+</ChangeBatch> \
+</ChangeResourceRecordSetsRequest>"
+
+fulldate=$(date --utc +%Y%m%dT%H%M%SZ)
+shortdate=$(date --utc +%Y%m%d)
+signed_headers="host;x-amz-date"
+request_hash=$(hash "$request_body")
+canonical_request="POST\n${API_PATH}\n\nhost:route53.amazonaws.com\nx-amz-date:${fulldate}\n\n${signed_headers}\n${request_hash}"
+
+date_key=$(sign_plain "AWS4${AWS_SECRET_ACCESS_KEY}" "${shortdate}")
+region_key=$(sign "$date_key" $AWS_REGION)
+service_key=$(sign "$region_key" $AWS_SERVICE)
+signing_key=$(sign "$service_key" aws4_request)
+
+credential="${shortdate}/${AWS_REGION}/${AWS_SERVICE}/aws4_request"
+sigmsg="AWS4-HMAC-SHA256\n${fulldate}\n${credential}\n$(hash "$canonical_request")"
+
+signature=$(sign "$signing_key" "$sigmsg")
+
+authorization="AWS4-HMAC-SHA256 Credential=${AWS_ACCESS_KEY_ID}/${credential}, SignedHeaders=${signed_headers}, Signature=${signature}"
+
+ANSWER=$(curl \
+    -X "POST" \
+    -H "Host: route53.amazonaws.com" \
+    -H "X-Amz-Date: ${fulldate}" \
+    -H "Authorization: ${authorization}" \
+    -H "Content-Type: text/xml" \
+    -d "$request_body" \
+    "https://${ENDPOINT}${API_PATH}")
+write_log 7 "${ANSWER}"
+
+echo ${ANSWER} | grep Error >/dev/null && return 1
+echo ${ANSWER} | grep ChangeInfo >/dev/null && return 0
+return 2