[Opendnssec-user] ODS 2.0.1 and using DNS Adapter

Mark Elkins mje at posix.co.za
Thu Sep 8 15:01:13 UTC 2016

I'm having a problem with ODS 2.0.1 and I'm using the DNS Adapter.

Setup is:

vhost1 ( - runs BIND 9.10.4-P2 - has an unsigned zone
which I keep updating.

vhost2 ( - runs ODS-2.0.1, it accepts inbound XFR from
vhost1. This had been working just fine.

vhost3 ( - runs BIND 9.10.4-P2 - pretends to be a
Distribution master. This always gets the latest zones that ODS offers.

I have a test zone "edu.za" that gets updated whenever necessary. its
actually an AXFR from a live master. Real changes are infrequent,
probably twice a week but the SOA is updated every night. Of course
today there have been 4 changes in one day.

Thus "vhost1" gets a new zone once an hour and sends an "rndc reload"
whenever the EDU.ZA  zone changes. EDU.ZA is actually signed with BIND -
hence I strip those records.

Cron Entry:

18 * * * * dig @160.124.xxx.xxx edu.za axfr | egrep -v
'RRSIG|NSEC|NSEC3|NSEC3PARAM|DNSKEY|^;' > /etc/ns.d/pri/edu.za/db.edu.za
&& rndc reload


I have a script that runs on vhost3 that does an AXFR from both vhost1
(unsigned) and vhost3 (signed). This script does various sanity checks.
I've attached it. Its run from cron at the same frequency that the
signer is configured to run - in this test case - every 10 minutes.

One check is that the signed zone should contain all the records of the
signed zone. Its seeing differences of stuff added to the unsigned zone
that never appear in the signed zone. The SOA Serial is now higher in
the unsigned zone (2016090804) than the signed zone (2016084331) - and I
am not seeing an ?XFR from vhost1 (Unsigned) to vhost2 (ODS).

On vhost1 (Unsigned, BIND), I've tried "rndc notify edu.za" - the
named.conf snippet includes:

zone "web.za" {
        type master;
        file "pri/edu.za/db.web.za";
        notify explicit;
        also-notify {; };

The intention is to *only* send notifies to and not to any
listed Nameservers, ie be explicit like NSD.

Thus - I presume that vhost2 (on would be correctly

The "rndc notify" gave me:

08-Sep-2016 13:03:04.022 received control channel command 'reload'
08-Sep-2016 13:03:04.023 zone edu.za/IN: loaded serial 2016090805
08-Sep-2016 13:03:04.023 zone edu.za/IN: sending notifies (serial


1 - Where can I see logs that would show such an action taking place (an
explicit NOTIFY) on the ODS machine?

2 - Can I get ODS to do an explicit query for a changed SOA?
(equivalent of: ods-signer sign edu.za - but for DNS {IA}XFR )


Incidentally - just a few minutes ago (after multiple hours of chasing
my tail) - there was an IXFR request from vhost2 (ODS) to the vhost1
(BIND) machine - so now everything is OK (The script no longer
complains)  - but the delay is still unexplained.

08-Sep-2016 14:32:37.980 client (edu.za): transfer
of 'edu.za/IN': AXFR-style IXFR started (serial 2016090805)
08-Sep-2016 14:32:37.981 client (edu.za): transfer
of 'edu.za/IN': AXFR-style IXFR ended

ps - very pleased to see IXFR working! (as opposed to just AXFR)

Mark James ELKINS  -  Posix Systems - (South) Africa
mje at posix.co.za       Tel: +27.128070590  Cell: +27.826010496
For fast, reliable, low cost Internet in ZA: https://ftth.posix.co.za
-------------- next part --------------

# IP Address of the Unsigned and Signed servers

# Values from KASP.xml - in minutes

# Zones we are checking, space separated - eg "posix.co.za edu.za other.com"


#==================  Nothing below here needs changing ================

# The lowest acceptable time to resigning an RRSIG record should be
# the Refresh time less the Resign Time.
# Reduce by an extra 30 seconds as a buffer.
Lowest=$(( ( ( $Refresh - $Resign ) * 60 ) - 30 ))

OUT="$0: run at $(date)"

# Zones I am checking
for zone in $ZONES
Transferring '$zone' zone ... "

dig @$UNSIGNED $zone axfr >$TF.unsigned.$zone
dig @$SIGNED $zone axfr >$TF.signed.$zone

DomainCnt=$(awk '/^[0-9a-zA-Z-]*\.'$zone'\./ { print $1 }' $TF.unsigned.$zone|sort -u|wc -l)
OUT="$OUT $DomainCnt Records"
egrep -v 'SOA|^;' $TF.unsigned.$zone|tr '[:upper:]' '[:lower:]'|sort|awk '{ $2=$3=""; print $0 }'>$TF.$zone-a
#egrep -v 'SOA|^;' $TF.unsigned.$zone|sort|awk '{ $2=$3=""; print $0 }'>$zone-a

egrep -v 'RRSIG|NSEC|NSEC3|NSEC3PARAM|DNSKEY|SOA|^;' $TF.signed.$zone|tr '[:upper:]' '[:lower:]'|sort|awk '{ $2=$3=""; print $0 }'> $TF.$zone-b
#egrep -v 'RRSIG|NSEC|NSEC3|NSEC3PARAM|DNSKEY|SOA|^;' $TF.signed.$zone|sort|awk '{ $2=$3=""; print $0 }'> $zone-b
diff $TF.$zone-a $TF.$zone-b > $TF.$zone-c
if [ -s $TF.$zone-c ] ; then
 Error - Diff between unsigned and signed
    $(cat $TF.$zone-c)"
    Signed and Unsigned zones compare OK"
rm -f $TF.$zone-a $TF.$zone-b $TF.$zone-c

# Read all RRSIG expire dates - check that the youngest is still suitable in the future
GMTSIGTIME=$(awk '/RRSIG/ { if($4=="RRSIG") print $9 }' $TF.signed.$zone|sort|head -1)
PrettyGMTtime=$(echo $GMTSIGTIME|sed 's^\(....\)\(..\)\(..\)\(..\)\(..\)\(..\)^\1-\2-\3 \4:\5:\6^')
RRSIGseconds=$(date --uct --date="$PrettyGMTtime" '+%s')

# Get our own clocks time
NowSeconds=$(date --uct '+%s')

# How long to go to expiry
ToGo=$(( $RRSIGseconds - $NowSeconds ))
    RRSIG Expire: $ToGo seconds (>$Lowest)"
[ $ToGo -lt $Lowest ] && Err=1 && OUT="$OUT
*** Warning: Signer may have stopped, Time to resigning is too low ***"

# Compare the Unsigned SOA to the Signed SOA
UnsignedSOA=$(dig +short @$UNSIGNED $zone soa|awk '{ print $3 }')
SignedSOA=$(dig +short @$SIGNED $zone soa|awk '{ print $3 }')
[ $SignedSOA -lt $UnsignedSOA ] && Err=1 && OUT="$OUT
Error: Signer has a lower Serial ($UnsignedSOA --> $SignedSOA)"

# For every Secure Delegation (there is a DS record) - Check there is an RRSIG Record.
for dom in $(awk '/DS/ { if($4=="DS") print $1 }' $TF.unsigned.$zone | sort -u)
TheSig=$(awk '/RRSIG/ { if($1=="'$dom'") print $10 }' $TF.signed.$zone)
if [ "$TheSig" == "" ] 
RRSIG Error: $dom has no RRSIG Record"
    CNT=$(( $CNT + 1 ))
    DSCNT=$(( $DSCNT + 1 ))

# Walk the Chain of NSEC3 records - from the SOA and back again.
START=$(grep NSEC3 $TF.signed.$zone | grep SOA | cut -d. -f1)
while [ "$FOUND" != "$START" ]
    CHAINS=$(( CHAINS + 1 ))
    FOUND=$(grep $NEXT $TF.signed.$zone | awk ' /NSEC3/ { if($4 != "RRSIG") print $9 }' |  tr '[:upper:]' '[:lower:]')
    if [ "$FOUND" == "" ] ; then
NSEC3 Chain Broken at entry $CHAINS: Badly chained NSEC3 hash at $NEXT.$zone."

rm -f $TF.unsigned.$zone $TF.signed.$zone

[ $Err -ne 0 ] && echo "$OUT"
exit $Err
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4230 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.opendnssec.org/pipermail/opendnssec-user/attachments/20160908/5d3625dd/attachment.bin>

More information about the Opendnssec-user mailing list