chiark / gitweb /
bin/update: Check current state before submitting an update. master
authorMark Wooding <mdw@distorted.org.uk>
Wed, 9 Sep 2015 23:29:00 +0000 (00:29 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Wed, 9 Sep 2015 23:29:00 +0000 (00:29 +0100)
Seems like this might reduce the work done by nameservers if they're not
very bright.

bin/update

index 60cbea08bc397a1b1aabaa75bd845215015f0fc2..5ff17fe42ff882b58079a3bcd74af703722fa2d7 100755 (executable)
@@ -28,6 +28,25 @@ EOF
 getarg='case $# in 0) fail_usage ;; esac; arg=$1; shift'
 doneargs='case $# in 0) ;; *) fail_usage ;; esac'
 
+check_current_state () {
+  ck_rrty=$1 ck_name=$2
+  set -- $(adnshost --config "nameserver $DYNDNS_SERVER" \
+           -Fi -Tt -t$ck_rrty "$ck_name")
+  case $1,$2,$3,$5 in
+    ";,failed,permfail,nxdomain" | ";,failed,permfail,nodata")
+      err=$5
+      ;;
+    ";,failed,"*)
+      shift 8
+      echo >&2 "$0: lookup $ck_name ($ck_rrty) failed: $*"
+      exit 4
+      ;;
+    *)
+      err=nil cur_ttl=$2 cur_addr=$4
+      ;;
+  esac
+}
+
 checkhost () {
   host=$1
 
@@ -47,13 +66,21 @@ checkhost () {
 
 doupdate () {
   cmd=$1
-
-nsupdate -k "$DYNDNS_KEY" <<EOF
+  case ${DYNDNS_TESTONLY_P-nil} in
+    nil)
+      nsupdate -k "$DYNDNS_KEY" <<EOF
 server $DYNDNS_SERVER
 zone $DYNDNS_ZONE
 $cmd
 send
 EOF
+      ;;
+    *)
+      cat <<EOF
+$cmd
+EOF
+      ;;
+  esac
 }
 
 eval $getarg; cmd=$arg
@@ -80,15 +107,24 @@ case "$cmd" in
       *) echo >&2 "$0: failed to parse new address"; exit 2 ;;
     esac
     name=$host.$DYNDNS_ZONE
+    check_current_state $(echo $rrtype | tr A-Z a-z) "$name"
+    ttl=${DYNDNS_TTL-14400}
+    case $err,$cur_ttl,$cur_addr in
+      nil,$ttl,$addr) echo >&2 "$0: nothing to do"; exit 0 ;;
+    esac
     doupdate "
        update delete $name IN $rrtype
-       update add $name ${DYNDNS_TTL-14400} IN $rrtype $addr"
+       update add $name $ttl IN $rrtype $addr"
     ;;
   unset)
     eval $getarg; host=$arg
     eval $doneargs
     checkhost "$host"
     name=$host.$DYNDNS_ZONE
+    check_current_state a "$name"
+    case $err in
+      nxdomain) echo >&2 "$0: nothing to do"; exit 0 ;;
+    esac
     doupdate "update delete $name IN"
     ;;
   *)