]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
also include all these new files.
authorYuri Schaeffer <yuri@nlnetlabs.nl>
Thu, 30 Apr 2015 07:48:03 +0000 (07:48 +0000)
committerYuri Schaeffer <yuri@nlnetlabs.nl>
Thu, 30 Apr 2015 07:48:03 +0000 (07:48 +0000)
git-svn-id: file:///svn/unbound/branches/edns-subnet@3416 be551aaa-1e26-0410-a405-d3ace91eadb9

54 files changed:
Makefile.in
compat/arc4_lock.c [new file with mode: 0644]
compat/arc4random.c [new file with mode: 0644]
compat/arc4random_uniform.c [new file with mode: 0644]
compat/chacha_private.h [new file with mode: 0644]
compat/explicit_bzero.c [new file with mode: 0644]
compat/getentropy_linux.c [new file with mode: 0644]
compat/getentropy_osx.c [new file with mode: 0644]
compat/getentropy_solaris.c [new file with mode: 0644]
compat/getentropy_win.c [new file with mode: 0644]
compat/reallocarray.c [new file with mode: 0644]
compat/sha512.c [new file with mode: 0644]
config.guess
config.sub
contrib/aaaa-filter-iterator.patch [new file with mode: 0644]
contrib/unbound_smf22.tar.gz [new file with mode: 0644]
dns64/dns64.c [new file with mode: 0644]
dns64/dns64.h [new file with mode: 0644]
dnstap/dnstap.c [new file with mode: 0644]
dnstap/dnstap.h [new file with mode: 0644]
dnstap/dnstap.m4 [new file with mode: 0644]
dnstap/dnstap.proto [new file with mode: 0644]
dnstap/dnstap_config.h.in [new file with mode: 0644]
doc/README.DNS64 [new file with mode: 0644]
libunbound/python/file_py3.i [new file with mode: 0644]
libunbound/worker.h [new file with mode: 0644]
ltmain.sh
sldns/keyraw.c [new file with mode: 0644]
sldns/keyraw.h [new file with mode: 0644]
sldns/parse.c [new file with mode: 0644]
sldns/parse.h [new file with mode: 0644]
sldns/parseutil.c [new file with mode: 0644]
sldns/parseutil.h [new file with mode: 0644]
sldns/pkthdr.h [new file with mode: 0644]
sldns/rrdef.c [new file with mode: 0644]
sldns/rrdef.h [new file with mode: 0644]
sldns/sbuffer.c [new file with mode: 0644]
sldns/sbuffer.h [new file with mode: 0644]
sldns/str2wire.c [new file with mode: 0644]
sldns/str2wire.h [new file with mode: 0644]
sldns/wire2str.c [new file with mode: 0644]
sldns/wire2str.h [new file with mode: 0644]
smallapp/unbound-control-setup.sh.in [moved from smallapp/unbound-control-setup.sh with 99% similarity, mode: 0644]
testcode/run_vm.sh [new file with mode: 0644]
testdata/ctrl_pipe.tpkg [new file with mode: 0644]
testdata/dlv_remove.rpl [new file with mode: 0644]
testdata/dlv_remove_empty.rpl [new file with mode: 0644]
testdata/dlv_remove_nodel.rpl [new file with mode: 0644]
testdata/dlv_remove_pos.rpl [new file with mode: 0644]
testdata/dns64_lookup.rpl [new file with mode: 0644]
testdata/fwd_capsid_strip.tpkg [new file with mode: 0644]
testdata/val_spurious_ns.rpl [new file with mode: 0644]
testdata/val_ta_algo_dnskey_dp.rpl [new file with mode: 0644]
testdata/val_ta_algo_missing_dp.rpl [new file with mode: 0644]

index c7f4937039cba0274e6f50f314fea29fd78e728e..7fb53ba04bb7c9cc60ac6f195121a7d4af47e186 100644 (file)
@@ -698,18 +698,6 @@ iter_utils.lo iter_utils.o: $(srcdir)/iterator/iter_utils.c config.h $(srcdir)/i
  $(srcdir)/services/modstack.h $(srcdir)/validator/val_anchor.h $(srcdir)/validator/val_kcache.h \
  $(srcdir)/validator/val_kentry.h $(srcdir)/validator/val_utils.h $(srcdir)/validator/val_sigcrypt.h \
  $(srcdir)/sldns/sbuffer.h
-edns-subnet.lo edns-subnet.o: $(srcdir)/edns-subnet/edns-subnet.c config.h $(srcdir)/edns-subnet/edns-subnet.h \
- $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/util/regional.h $(srcdir)/util/log.h \
- $(srcdir)/util/config_file.h \
- $(srcdir)/util/net_help.h
-subnet-whitelist.lo subnet-whitelist.o: $(srcdir)/edns-subnet/subnet-whitelist.c config.h $(srcdir)/edns-subnet/subnet-whitelist.h \
- $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/util/regional.h $(srcdir)/util/log.h \
- $(srcdir)/util/config_file.h \
- $(srcdir)/util/net_help.h
-subnetmod.lo subnetmod.o: $(srcdir)/edns-subnet/subnetmod.c config.h $(srcdir)/edns-subnet/subnetmod.h \
- $(srcdir)/util/config_file.h $(srcdir)/edns-subnet/addrtree.h $(srcdir)/edns-subnet/edns-subnet.h
-addrtree.lo addrtree.o: $(srcdir)/edns-subnet/addrtree.c config.h $(srcdir)/edns-subnet/addrtree.h \
- $(srcdir)/util/config_file.h
 listen_dnsport.lo listen_dnsport.o: $(srcdir)/services/listen_dnsport.c config.h \
  $(srcdir)/services/listen_dnsport.h $(srcdir)/util/netevent.h $(srcdir)/services/outside_network.h \
  $(srcdir)/util/rbtree.h  $(srcdir)/util/log.h $(srcdir)/util/config_file.h \
@@ -736,7 +724,7 @@ modstack.lo modstack.o: $(srcdir)/services/modstack.c config.h $(srcdir)/service
  $(srcdir)/validator/val_utils.h
 outbound_list.lo outbound_list.o: $(srcdir)/services/outbound_list.c config.h \
  $(srcdir)/services/outbound_list.h $(srcdir)/services/outside_network.h $(srcdir)/util/rbtree.h \
- $(srcdir)/util/netevent.h $(srcdir)/edns-subnet/subnetmod.h
+ $(srcdir)/util/netevent.h 
 outside_network.lo outside_network.o: $(srcdir)/services/outside_network.c config.h \
  $(srcdir)/services/outside_network.h $(srcdir)/util/rbtree.h $(srcdir)/util/netevent.h \
   $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/infra.h \
@@ -745,9 +733,7 @@ outside_network.lo outside_network.o: $(srcdir)/services/outside_network.c confi
  $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgencode.h \
  $(srcdir)/util/data/dname.h $(srcdir)/util/net_help.h $(srcdir)/util/random.h $(srcdir)/util/fptr_wlist.h \
  $(srcdir)/util/module.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/services/modstack.h \
- $(srcdir)/sldns/sbuffer.h $(srcdir)/dnstap/dnstap.h \
- $(srcdir)/edns-subnet/edns-subnet.h
+ $(srcdir)/sldns/sbuffer.h $(srcdir)/dnstap/dnstap.h
 alloc.lo alloc.o: $(srcdir)/util/alloc.c config.h $(srcdir)/util/alloc.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
  $(srcdir)/util/regional.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
  $(srcdir)/util/fptr_wlist.h $(srcdir)/util/netevent.h $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h \
@@ -795,14 +781,12 @@ netevent.lo netevent.o: $(srcdir)/util/netevent.c config.h $(srcdir)/util/neteve
  $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h \
  $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/tube.h \
  $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h $(srcdir)/sldns/sbuffer.h \
- $(srcdir)/dnstap/dnstap.h  \
- $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h
+ $(srcdir)/dnstap/dnstap.h  $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h
 net_help.lo net_help.o: $(srcdir)/util/net_help.c config.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h \
  $(srcdir)/util/data/dname.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/module.h \
  $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h \
  $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/regional.h $(srcdir)/sldns/parseutil.h \
- $(srcdir)/sldns/wire2str.h \
+ $(srcdir)/sldns/wire2str.h
 random.lo random.o: $(srcdir)/util/random.c config.h $(srcdir)/util/random.h $(srcdir)/util/log.h
 rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h $(srcdir)/util/fptr_wlist.h \
  $(srcdir)/util/netevent.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
@@ -837,8 +821,7 @@ autotrust.lo autotrust.o: $(srcdir)/validator/autotrust.c config.h $(srcdir)/val
  $(srcdir)/util/net_help.h $(srcdir)/util/config_file.h $(srcdir)/util/regional.h $(srcdir)/util/random.h \
  $(srcdir)/services/mesh.h $(srcdir)/util/netevent.h $(srcdir)/services/modstack.h \
  $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/validator/val_kcache.h \
- $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/wire2str.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/keyraw.h \
+ $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/wire2str.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/keyraw.h
 val_anchor.lo val_anchor.o: $(srcdir)/validator/val_anchor.c config.h $(srcdir)/validator/val_anchor.h \
  $(srcdir)/util/rbtree.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/validator/val_sigcrypt.h \
  $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/validator/autotrust.h \
@@ -863,22 +846,20 @@ val_kcache.lo val_kcache.o: $(srcdir)/validator/val_kcache.c config.h $(srcdir)/
 val_kentry.lo val_kentry.o: $(srcdir)/validator/val_kentry.c config.h $(srcdir)/validator/val_kentry.h \
  $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/data/packed_rrset.h \
  $(srcdir)/util/data/dname.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/regional.h $(srcdir)/util/net_help.h \
- $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/keyraw.h \
-val_neg.lo val_neg.o: $(srcdir)/validator/val_neg.c config.h \
- $(srcdir)/validator/val_neg.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/rbtree.h \
- $(srcdir)/validator/val_nsec.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
- $(srcdir)/validator/val_nsec3.h $(srcdir)/validator/val_utils.h $(srcdir)/util/data/dname.h \
- $(srcdir)/util/data/msgreply.h $(srcdir)/util/net_help.h $(srcdir)/util/config_file.h \
- $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/dns.h \
- $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/sbuffer.h
-val_nsec3.lo val_nsec3.o: $(srcdir)/validator/val_nsec3.c config.h \
- $(srcdir)/validator/val_nsec3.h $(srcdir)/util/rbtree.h $(srcdir)/util/data/packed_rrset.h \
- $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/validator/validator.h \
- $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \
- $(srcdir)/sldns/rrdef.h $(srcdir)/validator/val_utils.h $(srcdir)/validator/val_kentry.h \
- $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/util/regional.h \
- $(srcdir)/util/net_help.h $(srcdir)/util/data/dname.h $(srcdir)/validator/val_nsec.h $(srcdir)/sldns/sbuffer.h
+ $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/keyraw.h
+val_neg.lo val_neg.o: $(srcdir)/validator/val_neg.c config.h $(srcdir)/validator/val_neg.h $(srcdir)/util/locks.h \
+ $(srcdir)/util/log.h $(srcdir)/util/rbtree.h $(srcdir)/validator/val_nsec.h $(srcdir)/util/data/packed_rrset.h \
+ $(srcdir)/util/storage/lruhash.h $(srcdir)/validator/val_nsec3.h $(srcdir)/validator/val_utils.h \
+ $(srcdir)/util/data/dname.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/net_help.h \
+ $(srcdir)/util/config_file.h $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h \
+ $(srcdir)/services/cache/dns.h $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/sbuffer.h
+val_nsec3.lo val_nsec3.o: $(srcdir)/validator/val_nsec3.c config.h $(srcdir)/validator/val_nsec3.h \
+ $(srcdir)/util/rbtree.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
+ $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/validator/validator.h $(srcdir)/util/module.h \
+ $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h \
+ $(srcdir)/validator/val_utils.h $(srcdir)/validator/val_kentry.h $(srcdir)/services/cache/rrset.h \
+ $(srcdir)/util/storage/slabhash.h $(srcdir)/util/regional.h $(srcdir)/util/net_help.h \
+ $(srcdir)/util/data/dname.h $(srcdir)/validator/val_nsec.h $(srcdir)/sldns/sbuffer.h
 val_nsec.lo val_nsec.o: $(srcdir)/validator/val_nsec.c config.h $(srcdir)/validator/val_nsec.h \
  $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
  $(srcdir)/validator/val_utils.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/dname.h \
@@ -886,17 +867,14 @@ val_nsec.lo val_nsec.o: $(srcdir)/validator/val_nsec.c config.h $(srcdir)/valida
  $(srcdir)/sldns/rrdef.h $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h
 val_secalgo.lo val_secalgo.o: $(srcdir)/validator/val_secalgo.c config.h $(srcdir)/util/data/packed_rrset.h \
  $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/validator/val_secalgo.h \
- $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/keyraw.h \
- $(srcdir)/sldns/sbuffer.h \
+ $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/keyraw.h $(srcdir)/sldns/sbuffer.h
 val_sigcrypt.lo val_sigcrypt.o: $(srcdir)/validator/val_sigcrypt.c config.h \
  $(srcdir)/validator/val_sigcrypt.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
  $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/validator/val_secalgo.h $(srcdir)/validator/validator.h \
  $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \
  $(srcdir)/sldns/rrdef.h $(srcdir)/validator/val_utils.h $(srcdir)/util/data/dname.h $(srcdir)/util/rbtree.h \
- $(srcdir)/util/net_help.h $(srcdir)/util/regional.h $(srcdir)/sldns/keyraw.h \
- $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/parseutil.h $(srcdir)/sldns/wire2str.h \
+ $(srcdir)/util/net_help.h $(srcdir)/util/regional.h $(srcdir)/sldns/keyraw.h $(srcdir)/sldns/sbuffer.h \
+ $(srcdir)/sldns/parseutil.h $(srcdir)/sldns/wire2str.h
 val_utils.lo val_utils.o: $(srcdir)/validator/val_utils.c config.h $(srcdir)/validator/val_utils.h \
  $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
  $(srcdir)/validator/validator.h $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h \
@@ -905,6 +883,13 @@ val_utils.lo val_utils.o: $(srcdir)/validator/val_utils.c config.h $(srcdir)/val
  $(srcdir)/validator/val_nsec.h $(srcdir)/validator/val_neg.h $(srcdir)/services/cache/rrset.h \
  $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/dns.h $(srcdir)/util/data/dname.h \
  $(srcdir)/util/net_help.h $(srcdir)/util/regional.h
+edns-subnet.lo edns-subnet.o: $(srcdir)/edns-subnet/edns-subnet.c config.h
+subnetmod.lo subnetmod.o: $(srcdir)/edns-subnet/subnetmod.c config.h
+addrtree.lo addrtree.o: $(srcdir)/edns-subnet/addrtree.c config.h $(srcdir)/util/log.h \
+ $(srcdir)/util/data/msgreply.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h \
+ $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/module.h $(srcdir)/util/data/msgparse.h \
+ $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/edns-subnet/addrtree.h
+subnet-whitelist.lo subnet-whitelist.o: $(srcdir)/edns-subnet/subnet-whitelist.c config.h
 dns64.lo dns64.o: $(srcdir)/dns64/dns64.c config.h $(srcdir)/dns64/dns64.h $(srcdir)/util/module.h \
  $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/data/msgreply.h \
  $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \
@@ -914,11 +899,6 @@ dns64.lo dns64.o: $(srcdir)/dns64/dns64.c config.h $(srcdir)/dns64/dns64.h $(src
  $(srcdir)/services/modstack.h $(srcdir)/util/net_help.h $(srcdir)/util/regional.h
 checklocks.lo checklocks.o: $(srcdir)/testcode/checklocks.c config.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
  $(srcdir)/testcode/checklocks.h
-dnstap.lo dnstap.o: $(srcdir)/dnstap/dnstap.c  config.h $(srcdir)/sldns/sbuffer.h \
- $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h $(srcdir)/util/netevent.h \
- $(srcdir)/dnstap/dnstap.h \
- $(srcdir)/dnstap/dnstap.pb-c.h
-dnstap.pb-c.lo dnstap.pb-c.o: $(srcdir)/dnstap/dnstap.pb-c.c $(srcdir)/dnstap/dnstap.pb-c.h
 unitanchor.lo unitanchor.o: $(srcdir)/testcode/unitanchor.c config.h $(srcdir)/util/log.h $(srcdir)/util/data/dname.h \
  $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/testcode/unitmain.h \
  $(srcdir)/validator/val_anchor.h $(srcdir)/util/rbtree.h $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/rrdef.h
@@ -927,8 +907,7 @@ unitdname.lo unitdname.o: $(srcdir)/testcode/unitdname.c config.h $(srcdir)/util
  $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/rrdef.h
 unitlruhash.lo unitlruhash.o: $(srcdir)/testcode/unitlruhash.c config.h $(srcdir)/testcode/unitmain.h \
  $(srcdir)/util/log.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/storage/slabhash.h
-unitmain.lo unitmain.o: $(srcdir)/testcode/unitmain.c config.h \
- $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/keyraw.h \
+unitmain.lo unitmain.o: $(srcdir)/testcode/unitmain.c config.h $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/keyraw.h \
  $(srcdir)/util/log.h $(srcdir)/testcode/unitmain.h $(srcdir)/util/alloc.h $(srcdir)/util/locks.h $(srcdir)/util/net_help.h \
  $(srcdir)/util/config_file.h $(srcdir)/util/rtt.h $(srcdir)/services/cache/infra.h \
  $(srcdir)/util/storage/lruhash.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
@@ -939,9 +918,6 @@ unitmsgparse.lo unitmsgparse.o: $(srcdir)/testcode/unitmsgparse.c config.h $(src
  $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/dname.h \
  $(srcdir)/util/alloc.h $(srcdir)/util/regional.h $(srcdir)/util/net_help.h $(srcdir)/testcode/readhex.h \
  $(srcdir)/testcode/testpkts.h $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/wire2str.h
-unitvandergaast.lo unitvandergaast.o: $(srcdir)/testcode/unitvandergaast.c \
- config.h $(srcdir)/util/log.h  $(srcdir)/testcode/unitmain.h \
- $(srcdir)/edns-subnet/addrtree.h
 unitneg.lo unitneg.o: $(srcdir)/testcode/unitneg.c config.h $(srcdir)/util/log.h $(srcdir)/util/net_help.h \
  $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h \
  $(srcdir)/util/data/dname.h $(srcdir)/testcode/unitmain.h $(srcdir)/validator/val_neg.h $(srcdir)/util/rbtree.h \
@@ -966,41 +942,39 @@ testpkts.lo testpkts.o: $(srcdir)/testcode/testpkts.c config.h $(srcdir)/testcod
  $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/wire2str.h
 unitldns.lo unitldns.o: $(srcdir)/testcode/unitldns.c config.h $(srcdir)/util/log.h $(srcdir)/testcode/unitmain.h \
  $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/wire2str.h
+unitvandergaast.lo unitvandergaast.o: $(srcdir)/testcode/unitvandergaast.c config.h
 acl_list.lo acl_list.o: $(srcdir)/daemon/acl_list.c config.h $(srcdir)/daemon/acl_list.h \
  $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/util/regional.h $(srcdir)/util/log.h \
  $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h
-cachedump.lo cachedump.o: $(srcdir)/daemon/cachedump.c config.h \
- $(srcdir)/daemon/cachedump.h $(srcdir)/daemon/remote.h $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h \
- $(srcdir)/sldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
- $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/netevent.h $(srcdir)/util/alloc.h \
+cachedump.lo cachedump.o: $(srcdir)/daemon/cachedump.c config.h $(srcdir)/daemon/cachedump.h \
+ $(srcdir)/daemon/remote.h $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \
+ $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
+ $(srcdir)/util/netevent.h $(srcdir)/util/alloc.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h \
+ $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h \
+ $(srcdir)/util/module.h $(srcdir)/dnstap/dnstap.h  \
+ $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/dns.h \
+ $(srcdir)/services/cache/infra.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/util/rtt.h \
+ $(srcdir)/util/regional.h $(srcdir)/util/net_help.h $(srcdir)/util/data/dname.h $(srcdir)/iterator/iterator.h \
+ $(srcdir)/services/outbound_list.h $(srcdir)/iterator/iter_delegpt.h $(srcdir)/iterator/iter_utils.h \
+ $(srcdir)/iterator/iter_resptype.h $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h \
+ $(srcdir)/sldns/wire2str.h $(srcdir)/sldns/str2wire.h
+daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.h $(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h \
+ $(srcdir)/util/log.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h  \
+ $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \
+ $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/netevent.h \
  $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h \
  $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h $(srcdir)/dnstap/dnstap.h \
-  $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h \
- $(srcdir)/services/cache/dns.h $(srcdir)/services/cache/infra.h $(srcdir)/util/storage/dnstree.h \
- $(srcdir)/util/rbtree.h $(srcdir)/util/rtt.h $(srcdir)/util/regional.h $(srcdir)/util/net_help.h \
- $(srcdir)/util/data/dname.h $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h \
- $(srcdir)/iterator/iter_delegpt.h $(srcdir)/iterator/iter_utils.h $(srcdir)/iterator/iter_resptype.h \
- $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h $(srcdir)/sldns/wire2str.h \
- $(srcdir)/sldns/str2wire.h
-daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.h \
- $(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h \
-  $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h \
- $(srcdir)/sldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
- $(srcdir)/util/netevent.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \
- $(srcdir)/sldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h \
- $(srcdir)/dnstap/dnstap.h $(srcdir)/daemon/remote.h \
- $(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
+ $(srcdir)/daemon/remote.h $(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
  $(srcdir)/util/config_file.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/storage/slabhash.h \
  $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h \
  $(srcdir)/util/rtt.h $(srcdir)/services/localzone.h $(srcdir)/util/random.h $(srcdir)/util/tube.h \
  $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h
-remote.lo remote.o: $(srcdir)/daemon/remote.c config.h \
- $(srcdir)/daemon/remote.h \
- $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \
- $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
- $(srcdir)/util/netevent.h $(srcdir)/util/alloc.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h \
- $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h \
- $(srcdir)/util/module.h $(srcdir)/dnstap/dnstap.h  $(srcdir)/daemon/daemon.h \
+remote.lo remote.o: $(srcdir)/daemon/remote.c config.h $(srcdir)/daemon/remote.h $(srcdir)/daemon/worker.h \
+ $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h \
+ $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/netevent.h \
+ $(srcdir)/util/alloc.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \
+ $(srcdir)/sldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h \
+ $(srcdir)/dnstap/dnstap.h  $(srcdir)/daemon/daemon.h \
  $(srcdir)/services/modstack.h $(srcdir)/daemon/cachedump.h $(srcdir)/util/config_file.h \
  $(srcdir)/util/net_help.h $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h \
  $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/infra.h $(srcdir)/util/storage/dnstree.h \
@@ -1024,35 +998,33 @@ stats.lo stats.o: $(srcdir)/daemon/stats.c config.h $(srcdir)/daemon/stats.h $(s
  $(srcdir)/util/rtt.h $(srcdir)/validator/val_kcache.h
 unbound.lo unbound.o: $(srcdir)/daemon/unbound.c config.h $(srcdir)/util/log.h $(srcdir)/daemon/daemon.h \
  $(srcdir)/util/locks.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h  \
- $(srcdir)/daemon/remote.h \
- $(srcdir)/util/config_file.h $(srcdir)/util/storage/slabhash.h $(srcdir)/util/storage/lruhash.h \
- $(srcdir)/services/listen_dnsport.h $(srcdir)/util/netevent.h $(srcdir)/services/cache/rrset.h \
- $(srcdir)/util/data/packed_rrset.h $(srcdir)/services/cache/infra.h $(srcdir)/util/storage/dnstree.h \
- $(srcdir)/util/rbtree.h $(srcdir)/util/rtt.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/module.h \
- $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h \
- $(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/util/net_help.h $(srcdir)/util/mini_event.h \
- $(srcdir)/util/rbtree.h
+ $(srcdir)/daemon/remote.h $(srcdir)/util/config_file.h $(srcdir)/util/storage/slabhash.h \
+ $(srcdir)/util/storage/lruhash.h $(srcdir)/services/listen_dnsport.h $(srcdir)/util/netevent.h \
+ $(srcdir)/services/cache/rrset.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/services/cache/infra.h \
+ $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/util/rtt.h $(srcdir)/util/fptr_wlist.h \
+ $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \
+ $(srcdir)/sldns/rrdef.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/util/net_help.h \
+ $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h
 worker.lo worker.o: $(srcdir)/daemon/worker.c config.h $(srcdir)/util/log.h $(srcdir)/util/net_help.h \
  $(srcdir)/util/random.h $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \
  $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h \
  $(srcdir)/util/netevent.h $(srcdir)/util/alloc.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h \
  $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h \
  $(srcdir)/util/module.h $(srcdir)/dnstap/dnstap.h  $(srcdir)/daemon/daemon.h \
- $(srcdir)/services/modstack.h $(srcdir)/daemon/remote.h \
- $(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
- $(srcdir)/util/config_file.h $(srcdir)/util/regional.h $(srcdir)/util/storage/slabhash.h \
- $(srcdir)/services/listen_dnsport.h $(srcdir)/services/outside_network.h \
- $(srcdir)/services/outbound_list.h $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h \
- $(srcdir)/util/rtt.h $(srcdir)/services/cache/dns.h $(srcdir)/services/mesh.h $(srcdir)/services/localzone.h \
+ $(srcdir)/services/modstack.h $(srcdir)/daemon/remote.h $(srcdir)/daemon/acl_list.h \
+ $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/util/config_file.h $(srcdir)/util/regional.h \
+ $(srcdir)/util/storage/slabhash.h $(srcdir)/services/listen_dnsport.h \
+ $(srcdir)/services/outside_network.h $(srcdir)/services/outbound_list.h \
+ $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \
+ $(srcdir)/services/cache/dns.h $(srcdir)/services/mesh.h $(srcdir)/services/localzone.h \
  $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/dname.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h \
  $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h $(srcdir)/validator/autotrust.h \
  $(srcdir)/validator/val_anchor.h $(srcdir)/libunbound/context.h $(srcdir)/libunbound/unbound.h \
  $(srcdir)/libunbound/libworker.h
 testbound.lo testbound.o: $(srcdir)/testcode/testbound.c config.h $(srcdir)/testcode/testpkts.h \
  $(srcdir)/testcode/replay.h $(srcdir)/util/netevent.h $(srcdir)/util/rbtree.h $(srcdir)/testcode/fake_event.h \
- $(srcdir)/daemon/remote.h \
- $(srcdir)/util/config_file.h $(srcdir)/sldns/keyraw.h $(srcdir)/daemon/unbound.c $(srcdir)/util/log.h \
- $(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h \
+ $(srcdir)/daemon/remote.h $(srcdir)/util/config_file.h $(srcdir)/sldns/keyraw.h $(srcdir)/daemon/unbound.c \
+ $(srcdir)/util/log.h $(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h \
   $(srcdir)/util/storage/slabhash.h $(srcdir)/util/storage/lruhash.h \
  $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h \
  $(srcdir)/util/data/packed_rrset.h $(srcdir)/services/cache/infra.h $(srcdir)/util/storage/dnstree.h \
@@ -1068,12 +1040,12 @@ worker.lo worker.o: $(srcdir)/daemon/worker.c config.h $(srcdir)/util/log.h $(sr
  $(srcdir)/util/netevent.h $(srcdir)/util/alloc.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h \
  $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h \
  $(srcdir)/util/module.h $(srcdir)/dnstap/dnstap.h  $(srcdir)/daemon/daemon.h \
- $(srcdir)/services/modstack.h $(srcdir)/daemon/remote.h \
- $(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
- $(srcdir)/util/config_file.h $(srcdir)/util/regional.h $(srcdir)/util/storage/slabhash.h \
- $(srcdir)/services/listen_dnsport.h $(srcdir)/services/outside_network.h \
- $(srcdir)/services/outbound_list.h $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h \
- $(srcdir)/util/rtt.h $(srcdir)/services/cache/dns.h $(srcdir)/services/mesh.h $(srcdir)/services/localzone.h \
+ $(srcdir)/services/modstack.h $(srcdir)/daemon/remote.h $(srcdir)/daemon/acl_list.h \
+ $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/util/config_file.h $(srcdir)/util/regional.h \
+ $(srcdir)/util/storage/slabhash.h $(srcdir)/services/listen_dnsport.h \
+ $(srcdir)/services/outside_network.h $(srcdir)/services/outbound_list.h \
+ $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \
+ $(srcdir)/services/cache/dns.h $(srcdir)/services/mesh.h $(srcdir)/services/localzone.h \
  $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/dname.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h \
  $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h $(srcdir)/validator/autotrust.h \
  $(srcdir)/validator/val_anchor.h $(srcdir)/libunbound/context.h $(srcdir)/libunbound/unbound.h \
@@ -1081,18 +1053,17 @@ worker.lo worker.o: $(srcdir)/daemon/worker.c config.h $(srcdir)/util/log.h $(sr
 acl_list.lo acl_list.o: $(srcdir)/daemon/acl_list.c config.h $(srcdir)/daemon/acl_list.h \
  $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/util/regional.h $(srcdir)/util/log.h \
  $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h
-daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.h \
- $(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h \
-  $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h \
- $(srcdir)/sldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
- $(srcdir)/util/netevent.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \
- $(srcdir)/sldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h \
- $(srcdir)/dnstap/dnstap.h $(srcdir)/daemon/remote.h \
- $(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
+daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.h $(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h \
+ $(srcdir)/util/log.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h  \
+ $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \
+ $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/netevent.h \
+ $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h \
+ $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h $(srcdir)/dnstap/dnstap.h \
+ $(srcdir)/daemon/remote.h $(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
  $(srcdir)/util/config_file.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/storage/slabhash.h \
  $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h \
  $(srcdir)/util/rtt.h $(srcdir)/services/localzone.h $(srcdir)/util/random.h $(srcdir)/util/tube.h \
- $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h $(srcdir)/edns-subnet/edns-subnet.h
+ $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h
 stats.lo stats.o: $(srcdir)/daemon/stats.c config.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h \
  $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \
  $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
@@ -1163,19 +1134,18 @@ libunbound.lo libunbound.o: $(srcdir)/libunbound/libunbound.c $(srcdir)/libunbou
  $(srcdir)/util/random.h $(srcdir)/util/net_help.h $(srcdir)/util/tube.h $(srcdir)/services/localzone.h \
  $(srcdir)/services/cache/infra.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rtt.h \
  $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/sldns/sbuffer.h
-libworker.lo libworker.o: $(srcdir)/libunbound/libworker.c config.h \
- $(srcdir)/libunbound/libworker.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
- $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/libunbound/context.h $(srcdir)/util/alloc.h $(srcdir)/util/rbtree.h \
- $(srcdir)/services/modstack.h $(srcdir)/libunbound/unbound.h $(srcdir)/libunbound/worker.h \
- $(srcdir)/sldns/sbuffer.h $(srcdir)/libunbound/unbound-event.h $(srcdir)/services/outside_network.h \
- $(srcdir)/util/netevent.h  $(srcdir)/services/mesh.h \
- $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/module.h \
- $(srcdir)/util/data/msgreply.h $(srcdir)/services/localzone.h $(srcdir)/services/cache/rrset.h \
- $(srcdir)/util/storage/slabhash.h $(srcdir)/services/outbound_list.h $(srcdir)/util/fptr_wlist.h \
- $(srcdir)/util/tube.h $(srcdir)/util/regional.h $(srcdir)/util/random.h $(srcdir)/util/config_file.h \
- $(srcdir)/util/storage/lookup3.h $(srcdir)/util/net_help.h $(srcdir)/util/data/dname.h \
- $(srcdir)/util/data/msgencode.h $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h \
- $(srcdir)/util/storage/dnstree.h $(srcdir)/sldns/str2wire.h
+libworker.lo libworker.o: $(srcdir)/libunbound/libworker.c config.h $(srcdir)/libunbound/libworker.h \
+ $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
+ $(srcdir)/libunbound/context.h $(srcdir)/util/alloc.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h \
+ $(srcdir)/libunbound/unbound.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \
+ $(srcdir)/libunbound/unbound-event.h $(srcdir)/services/outside_network.h $(srcdir)/util/netevent.h \
+  $(srcdir)/services/mesh.h $(srcdir)/util/data/msgparse.h \
+ $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h \
+ $(srcdir)/services/localzone.h $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h \
+ $(srcdir)/services/outbound_list.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/util/regional.h \
+ $(srcdir)/util/random.h $(srcdir)/util/config_file.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/net_help.h \
+ $(srcdir)/util/data/dname.h $(srcdir)/util/data/msgencode.h $(srcdir)/iterator/iter_fwd.h \
+ $(srcdir)/iterator/iter_hints.h $(srcdir)/util/storage/dnstree.h $(srcdir)/sldns/str2wire.h
 unbound-host.lo unbound-host.o: $(srcdir)/smallapp/unbound-host.c config.h $(srcdir)/libunbound/unbound.h \
  $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/wire2str.h
 asynclook.lo asynclook.o: $(srcdir)/testcode/asynclook.c config.h $(srcdir)/libunbound/unbound.h \
@@ -1186,21 +1156,18 @@ streamtcp.lo streamtcp.o: $(srcdir)/testcode/streamtcp.c config.h $(srcdir)/util
  $(srcdir)/util/net_help.h $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/msgparse.h \
  $(srcdir)/util/storage/lruhash.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/data/msgreply.h \
  $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/dname.h $(srcdir)/sldns/sbuffer.h \
- $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/wire2str.h \
+ $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/wire2str.h
 perf.lo perf.o: $(srcdir)/testcode/perf.c config.h $(srcdir)/util/log.h $(srcdir)/util/locks.h $(srcdir)/util/net_help.h \
  $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/storage/lruhash.h \
  $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \
  $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/wire2str.h $(srcdir)/sldns/str2wire.h
 delayer.lo delayer.o: $(srcdir)/testcode/delayer.c config.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h \
  $(srcdir)/util/config_file.h $(srcdir)/sldns/sbuffer.h
-unbound-control.lo unbound-control.o: $(srcdir)/smallapp/unbound-control.c config.h \
- $(srcdir)/util/log.h $(srcdir)/util/config_file.h $(srcdir)/util/locks.h $(srcdir)/util/net_help.h
+unbound-control.lo unbound-control.o: $(srcdir)/smallapp/unbound-control.c config.h $(srcdir)/util/log.h \
+ $(srcdir)/util/config_file.h $(srcdir)/util/locks.h $(srcdir)/util/net_help.h
 unbound-anchor.lo unbound-anchor.o: $(srcdir)/smallapp/unbound-anchor.c config.h $(srcdir)/libunbound/unbound.h \
- $(srcdir)/sldns/rrdef.h \
-petal.lo petal.o: $(srcdir)/testcode/petal.c config.h \
+ $(srcdir)/sldns/rrdef.h
+petal.lo petal.o: $(srcdir)/testcode/petal.c config.h
 pythonmod_utils.lo pythonmod_utils.o: $(srcdir)/pythonmod/pythonmod_utils.c config.h $(srcdir)/util/module.h \
  $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/data/msgreply.h \
  $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \
@@ -1213,8 +1180,7 @@ win_svc.lo win_svc.o: $(srcdir)/winrc/win_svc.c config.h $(srcdir)/winrc/win_svc
  $(srcdir)/sldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \
  $(srcdir)/util/netevent.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \
  $(srcdir)/sldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h \
- $(srcdir)/dnstap/dnstap.h $(srcdir)/daemon/remote.h \
- $(srcdir)/util/config_file.h $(srcdir)/util/winsock_event.h
+ $(srcdir)/dnstap/dnstap.h $(srcdir)/daemon/remote.h $(srcdir)/util/config_file.h $(srcdir)/util/winsock_event.h
 w_inst.lo w_inst.o: $(srcdir)/winrc/w_inst.c config.h $(srcdir)/winrc/w_inst.h $(srcdir)/winrc/win_svc.h
 unbound-service-install.lo unbound-service-install.o: $(srcdir)/winrc/unbound-service-install.c config.h \
  $(srcdir)/winrc/w_inst.h
@@ -1222,14 +1188,11 @@ unbound-service-remove.lo unbound-service-remove.o: $(srcdir)/winrc/unbound-serv
  $(srcdir)/winrc/w_inst.h
 anchor-update.lo anchor-update.o: $(srcdir)/winrc/anchor-update.c config.h $(srcdir)/libunbound/unbound.h \
  $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/wire2str.h
-keyraw.lo keyraw.o: $(srcdir)/sldns/keyraw.c config.h $(srcdir)/sldns/keyraw.h \
- $(srcdir)/sldns/rrdef.h \
+keyraw.lo keyraw.o: $(srcdir)/sldns/keyraw.c config.h $(srcdir)/sldns/keyraw.h $(srcdir)/sldns/rrdef.h
 sbuffer.lo sbuffer.o: $(srcdir)/sldns/sbuffer.c config.h $(srcdir)/sldns/sbuffer.h
 wire2str.lo wire2str.o: $(srcdir)/sldns/wire2str.c config.h $(srcdir)/sldns/wire2str.h $(srcdir)/sldns/str2wire.h \
  $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/parseutil.h $(srcdir)/sldns/sbuffer.h \
- $(srcdir)/sldns/keyraw.h \
+ $(srcdir)/sldns/keyraw.h
 parse.lo parse.o: $(srcdir)/sldns/parse.c config.h $(srcdir)/sldns/parse.h $(srcdir)/sldns/parseutil.h \
  $(srcdir)/sldns/sbuffer.h
 parseutil.lo parseutil.o: $(srcdir)/sldns/parseutil.c config.h $(srcdir)/sldns/parseutil.h
@@ -1249,8 +1212,7 @@ snprintf.lo snprintf.o: $(srcdir)/compat/snprintf.c config.h
 strlcat.lo strlcat.o: $(srcdir)/compat/strlcat.c config.h
 strlcpy.lo strlcpy.o: $(srcdir)/compat/strlcpy.c config.h
 strptime.lo strptime.o: $(srcdir)/compat/strptime.c config.h
-getentropy_linux.lo getentropy_linux.o: $(srcdir)/compat/getentropy_linux.c config.h \
+getentropy_linux.lo getentropy_linux.o: $(srcdir)/compat/getentropy_linux.c config.h
 getentropy_osx.lo getentropy_osx.o: $(srcdir)/compat/getentropy_osx.c config.h
 getentropy_solaris.lo getentropy_solaris.o: $(srcdir)/compat/getentropy_solaris.c config.h
 getentropy_win.lo getentropy_win.o: $(srcdir)/compat/getentropy_win.c
diff --git a/compat/arc4_lock.c b/compat/arc4_lock.c
new file mode 100644 (file)
index 0000000..faa743d
--- /dev/null
@@ -0,0 +1,67 @@
+/* arc4_lock.c - global lock for arc4random
+*
+ * Copyright (c) 2014, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#define LOCKRET(func) func
+#include "util/locks.h"
+
+void _ARC4_LOCK(void);
+void _ARC4_UNLOCK(void);
+
+#ifdef THREADS_DISABLED
+void _ARC4_LOCK(void)
+{
+}
+
+void _ARC4_UNLOCK(void)
+{
+}
+#else /* !THREADS_DISABLED */
+
+static lock_quick_t arc4lock;
+static int arc4lockinit = 0;
+
+void _ARC4_LOCK(void)
+{
+       if(!arc4lockinit) {
+               arc4lockinit = 1;
+               lock_quick_init(&arc4lock);
+       }
+       lock_quick_lock(&arc4lock);
+}
+
+void _ARC4_UNLOCK(void)
+{
+       lock_quick_unlock(&arc4lock);
+}
+#endif /* THREADS_DISABLED */
diff --git a/compat/arc4random.c b/compat/arc4random.c
new file mode 100644 (file)
index 0000000..27a626b
--- /dev/null
@@ -0,0 +1,231 @@
+/*      $OpenBSD: arc4random.c,v 1.41 2014/07/12 13:24:54 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+/*
+ * ChaCha based random number generator for OpenBSD.
+ */
+
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#ifndef UB_ON_WINDOWS
+#include <sys/mman.h>
+#endif
+
+#define KEYSTREAM_ONLY
+#include "chacha_private.h"
+
+#define arc4_min(a, b) ((a) < (b) ? (a) : (b))
+#ifdef __GNUC__
+#define inline __inline
+#else                          /* !__GNUC__ */
+#define inline
+#endif                         /* !__GNUC__ */
+
+#define KEYSZ  32
+#define IVSZ   8
+#define BLOCKSZ        64
+#define RSBUFSZ        (16*BLOCKSZ)
+
+/* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */
+static struct {
+       size_t          rs_have;        /* valid bytes at end of rs_buf */
+       size_t          rs_count;       /* bytes till reseed */
+} *rs;
+
+/* Preserved in fork children. */
+static struct {
+       chacha_ctx      rs_chacha;      /* chacha context for random keystream */
+       u_char          rs_buf[RSBUFSZ];        /* keystream blocks */
+} *rsx;
+
+static inline void _rs_rekey(u_char *dat, size_t datlen);
+
+static inline void
+_rs_init(u_char *buf, size_t n)
+{
+       if (n < KEYSZ + IVSZ)
+               return;
+
+       if (rs == NULL) {
+#ifndef UB_ON_WINDOWS
+               if ((rs = mmap(NULL, sizeof(*rs), PROT_READ|PROT_WRITE,
+                   MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
+                       abort();
+#ifdef MAP_INHERIT_ZERO
+               if (minherit(rs, sizeof(*rs), MAP_INHERIT_ZERO) == -1)
+                       abort();
+#endif
+#else /* WINDOWS */
+               rs = malloc(sizeof(*rs));
+               if(!rs)
+                       abort();
+#endif
+       }
+       if (rsx == NULL) {
+#ifndef UB_ON_WINDOWS
+               if ((rsx = mmap(NULL, sizeof(*rsx), PROT_READ|PROT_WRITE,
+                   MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
+                       abort();
+#else /* WINDOWS */
+               rsx = malloc(sizeof(*rsx));
+               if(!rsx)
+                       abort();
+#endif
+       }
+
+       chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8, 0);
+       chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ);
+}
+
+static void
+_rs_stir(void)
+{
+       u_char rnd[KEYSZ + IVSZ];
+
+       if (getentropy(rnd, sizeof rnd) == -1) {
+#ifdef SIGKILL
+               raise(SIGKILL);
+#else
+               exit(9); /* windows */
+#endif
+       }
+
+       if (!rs)
+               _rs_init(rnd, sizeof(rnd));
+       else
+               _rs_rekey(rnd, sizeof(rnd));
+       explicit_bzero(rnd, sizeof(rnd));       /* discard source seed */
+
+       /* invalidate rs_buf */
+       rs->rs_have = 0;
+       memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
+
+       rs->rs_count = 1600000;
+}
+
+static inline void
+_rs_stir_if_needed(size_t len)
+{
+#ifndef MAP_INHERIT_ZERO
+       static pid_t _rs_pid = 0;
+       pid_t pid = getpid();
+
+       /* If a system lacks MAP_INHERIT_ZERO, resort to getpid() */
+       if (_rs_pid == 0 || _rs_pid != pid) {
+               _rs_pid = pid;
+               if (rs)
+                       rs->rs_count = 0;
+       }
+#endif
+       if (!rs || rs->rs_count <= len)
+               _rs_stir();
+       if (rs->rs_count <= len)
+               rs->rs_count = 0;
+       else
+               rs->rs_count -= len;
+}
+
+static inline void
+_rs_rekey(u_char *dat, size_t datlen)
+{
+#ifndef KEYSTREAM_ONLY
+       memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
+#endif
+       /* fill rs_buf with the keystream */
+       chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf,
+           rsx->rs_buf, sizeof(rsx->rs_buf));
+       /* mix in optional user provided data */
+       if (dat) {
+               size_t i, m;
+
+               m = arc4_min(datlen, KEYSZ + IVSZ);
+               for (i = 0; i < m; i++)
+                       rsx->rs_buf[i] ^= dat[i];
+       }
+       /* immediately reinit for backtracking resistance */
+       _rs_init(rsx->rs_buf, KEYSZ + IVSZ);
+       memset(rsx->rs_buf, 0, KEYSZ + IVSZ);
+       rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ;
+}
+
+static inline void
+_rs_random_buf(void *_buf, size_t n)
+{
+       u_char *buf = (u_char *)_buf;
+       u_char *keystream;
+       size_t m;
+
+       _rs_stir_if_needed(n);
+       while (n > 0) {
+               if (rs->rs_have > 0) {
+                       m = arc4_min(n, rs->rs_have);
+                       keystream = rsx->rs_buf + sizeof(rsx->rs_buf)
+                           - rs->rs_have;
+                       memcpy(buf, keystream, m);
+                       memset(keystream, 0, m);
+                       buf += m;
+                       n -= m;
+                       rs->rs_have -= m;
+               }
+               if (rs->rs_have == 0)
+                       _rs_rekey(NULL, 0);
+       }
+}
+
+static inline void
+_rs_random_u32(uint32_t *val)
+{
+       u_char *keystream;
+       _rs_stir_if_needed(sizeof(*val));
+       if (rs->rs_have < sizeof(*val))
+               _rs_rekey(NULL, 0);
+       keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have;
+       memcpy(val, keystream, sizeof(*val));
+       memset(keystream, 0, sizeof(*val));
+       rs->rs_have -= sizeof(*val);
+}
+
+uint32_t
+arc4random(void)
+{
+       uint32_t val;
+
+       _ARC4_LOCK();
+       _rs_random_u32(&val);
+       _ARC4_UNLOCK();
+       return val;
+}
+
+void
+arc4random_buf(void *buf, size_t n)
+{
+       _ARC4_LOCK();
+       _rs_random_buf(buf, n);
+       _ARC4_UNLOCK();
+}
diff --git a/compat/arc4random_uniform.c b/compat/arc4random_uniform.c
new file mode 100644 (file)
index 0000000..154260e
--- /dev/null
@@ -0,0 +1,57 @@
+/*      $OpenBSD: arc4random_uniform.c,v 1.1 2014/07/12 13:24:54 deraadt Exp $  */
+
+/*
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+#include <sys/types.h>
+#include <stdlib.h>
+
+/*
+ * Calculate a uniformly distributed random number less than upper_bound
+ * avoiding "modulo bias".
+ *
+ * Uniformity is achieved by generating new random numbers until the one
+ * returned is outside the range [0, 2**32 % upper_bound).  This
+ * guarantees the selected random number will be inside
+ * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
+ * after reduction modulo upper_bound.
+ */
+uint32_t
+arc4random_uniform(uint32_t upper_bound)
+{
+       uint32_t r, min;
+
+       if (upper_bound < 2)
+               return 0;
+
+       /* 2**32 % x == (2**32 - x) % x */
+       min = -upper_bound % upper_bound;
+
+       /*
+        * This could theoretically loop forever but each retry has
+        * p > 0.5 (worst case, usually far better) of selecting a
+        * number inside the range we need, so it should rarely need
+        * to re-roll.
+        */
+       for (;;) {
+               r = arc4random();
+               if (r >= min)
+                       break;
+       }
+
+       return r % upper_bound;
+}
diff --git a/compat/chacha_private.h b/compat/chacha_private.h
new file mode 100644 (file)
index 0000000..192258c
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+chacha-merged.c version 20080118
+D. J. Bernstein
+Public domain.
+*/
+
+/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */
+
+typedef unsigned char u8;
+typedef unsigned int u32;
+
+typedef struct
+{
+  u32 input[16]; /* could be compressed */
+} chacha_ctx;
+
+#define U8C(v) (v##U)
+#define U32C(v) (v##U)
+
+#define U8V(v) ((u8)(v) & U8C(0xFF))
+#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
+
+#define ROTL32(v, n) \
+  (U32V((v) << (n)) | ((v) >> (32 - (n))))
+
+#define U8TO32_LITTLE(p) \
+  (((u32)((p)[0])      ) | \
+   ((u32)((p)[1]) <<  8) | \
+   ((u32)((p)[2]) << 16) | \
+   ((u32)((p)[3]) << 24))
+
+#define U32TO8_LITTLE(p, v) \
+  do { \
+    (p)[0] = U8V((v)      ); \
+    (p)[1] = U8V((v) >>  8); \
+    (p)[2] = U8V((v) >> 16); \
+    (p)[3] = U8V((v) >> 24); \
+  } while (0)
+
+#define ROTATE(v,c) (ROTL32(v,c))
+#define XOR(v,w) ((v) ^ (w))
+#define PLUS(v,w) (U32V((v) + (w)))
+#define PLUSONE(v) (PLUS((v),1))
+
+#define QUARTERROUND(a,b,c,d) \
+  a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
+  c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
+  a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
+  c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
+
+static const char sigma[16] = "expand 32-byte k";
+static const char tau[16] = "expand 16-byte k";
+
+static void
+chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ATTR_UNUSED(ivbits))
+{
+  const char *constants;
+
+  x->input[4] = U8TO32_LITTLE(k + 0);
+  x->input[5] = U8TO32_LITTLE(k + 4);
+  x->input[6] = U8TO32_LITTLE(k + 8);
+  x->input[7] = U8TO32_LITTLE(k + 12);
+  if (kbits == 256) { /* recommended */
+    k += 16;
+    constants = sigma;
+  } else { /* kbits == 128 */
+    constants = tau;
+  }
+  x->input[8] = U8TO32_LITTLE(k + 0);
+  x->input[9] = U8TO32_LITTLE(k + 4);
+  x->input[10] = U8TO32_LITTLE(k + 8);
+  x->input[11] = U8TO32_LITTLE(k + 12);
+  x->input[0] = U8TO32_LITTLE(constants + 0);
+  x->input[1] = U8TO32_LITTLE(constants + 4);
+  x->input[2] = U8TO32_LITTLE(constants + 8);
+  x->input[3] = U8TO32_LITTLE(constants + 12);
+}
+
+static void
+chacha_ivsetup(chacha_ctx *x,const u8 *iv)
+{
+  x->input[12] = 0;
+  x->input[13] = 0;
+  x->input[14] = U8TO32_LITTLE(iv + 0);
+  x->input[15] = U8TO32_LITTLE(iv + 4);
+}
+
+static void
+chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
+{
+  u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+  u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+  u8 *ctarget = NULL;
+  u8 tmp[64];
+  u_int i;
+
+  if (!bytes) return;
+
+  j0 = x->input[0];
+  j1 = x->input[1];
+  j2 = x->input[2];
+  j3 = x->input[3];
+  j4 = x->input[4];
+  j5 = x->input[5];
+  j6 = x->input[6];
+  j7 = x->input[7];
+  j8 = x->input[8];
+  j9 = x->input[9];
+  j10 = x->input[10];
+  j11 = x->input[11];
+  j12 = x->input[12];
+  j13 = x->input[13];
+  j14 = x->input[14];
+  j15 = x->input[15];
+
+  for (;;) {
+    if (bytes < 64) {
+      for (i = 0;i < bytes;++i) tmp[i] = m[i];
+      m = tmp;
+      ctarget = c;
+      c = tmp;
+    }
+    x0 = j0;
+    x1 = j1;
+    x2 = j2;
+    x3 = j3;
+    x4 = j4;
+    x5 = j5;
+    x6 = j6;
+    x7 = j7;
+    x8 = j8;
+    x9 = j9;
+    x10 = j10;
+    x11 = j11;
+    x12 = j12;
+    x13 = j13;
+    x14 = j14;
+    x15 = j15;
+    for (i = 20;i > 0;i -= 2) {
+      QUARTERROUND( x0, x4, x8,x12)
+      QUARTERROUND( x1, x5, x9,x13)
+      QUARTERROUND( x2, x6,x10,x14)
+      QUARTERROUND( x3, x7,x11,x15)
+      QUARTERROUND( x0, x5,x10,x15)
+      QUARTERROUND( x1, x6,x11,x12)
+      QUARTERROUND( x2, x7, x8,x13)
+      QUARTERROUND( x3, x4, x9,x14)
+    }
+    x0 = PLUS(x0,j0);
+    x1 = PLUS(x1,j1);
+    x2 = PLUS(x2,j2);
+    x3 = PLUS(x3,j3);
+    x4 = PLUS(x4,j4);
+    x5 = PLUS(x5,j5);
+    x6 = PLUS(x6,j6);
+    x7 = PLUS(x7,j7);
+    x8 = PLUS(x8,j8);
+    x9 = PLUS(x9,j9);
+    x10 = PLUS(x10,j10);
+    x11 = PLUS(x11,j11);
+    x12 = PLUS(x12,j12);
+    x13 = PLUS(x13,j13);
+    x14 = PLUS(x14,j14);
+    x15 = PLUS(x15,j15);
+
+#ifndef KEYSTREAM_ONLY
+    x0 = XOR(x0,U8TO32_LITTLE(m + 0));
+    x1 = XOR(x1,U8TO32_LITTLE(m + 4));
+    x2 = XOR(x2,U8TO32_LITTLE(m + 8));
+    x3 = XOR(x3,U8TO32_LITTLE(m + 12));
+    x4 = XOR(x4,U8TO32_LITTLE(m + 16));
+    x5 = XOR(x5,U8TO32_LITTLE(m + 20));
+    x6 = XOR(x6,U8TO32_LITTLE(m + 24));
+    x7 = XOR(x7,U8TO32_LITTLE(m + 28));
+    x8 = XOR(x8,U8TO32_LITTLE(m + 32));
+    x9 = XOR(x9,U8TO32_LITTLE(m + 36));
+    x10 = XOR(x10,U8TO32_LITTLE(m + 40));
+    x11 = XOR(x11,U8TO32_LITTLE(m + 44));
+    x12 = XOR(x12,U8TO32_LITTLE(m + 48));
+    x13 = XOR(x13,U8TO32_LITTLE(m + 52));
+    x14 = XOR(x14,U8TO32_LITTLE(m + 56));
+    x15 = XOR(x15,U8TO32_LITTLE(m + 60));
+#endif
+
+    j12 = PLUSONE(j12);
+    if (!j12) {
+      j13 = PLUSONE(j13);
+      /* stopping at 2^70 bytes per nonce is user's responsibility */
+    }
+
+    U32TO8_LITTLE(c + 0,x0);
+    U32TO8_LITTLE(c + 4,x1);
+    U32TO8_LITTLE(c + 8,x2);
+    U32TO8_LITTLE(c + 12,x3);
+    U32TO8_LITTLE(c + 16,x4);
+    U32TO8_LITTLE(c + 20,x5);
+    U32TO8_LITTLE(c + 24,x6);
+    U32TO8_LITTLE(c + 28,x7);
+    U32TO8_LITTLE(c + 32,x8);
+    U32TO8_LITTLE(c + 36,x9);
+    U32TO8_LITTLE(c + 40,x10);
+    U32TO8_LITTLE(c + 44,x11);
+    U32TO8_LITTLE(c + 48,x12);
+    U32TO8_LITTLE(c + 52,x13);
+    U32TO8_LITTLE(c + 56,x14);
+    U32TO8_LITTLE(c + 60,x15);
+
+    if (bytes <= 64) {
+      if (bytes < 64) {
+        for (i = 0;i < bytes;++i) ctarget[i] = c[i];
+      }
+      x->input[12] = j12;
+      x->input[13] = j13;
+      return;
+    }
+    bytes -= 64;
+    c += 64;
+#ifndef KEYSTREAM_ONLY
+    m += 64;
+#endif
+  }
+}
diff --git a/compat/explicit_bzero.c b/compat/explicit_bzero.c
new file mode 100644 (file)
index 0000000..a3ba279
--- /dev/null
@@ -0,0 +1,22 @@
+/*     $OpenBSD: explicit_bzero.c,v 1.3 2014/06/21 02:34:26 matthew Exp $ */
+/*
+ * Public domain.
+ * Written by Matthew Dempsky.
+ */
+#include "config.h"
+#include <string.h>
+
+__attribute__((weak)) void
+__explicit_bzero_hook(void *ATTR_UNUSED(buf), size_t ATTR_UNUSED(len))
+{
+}
+
+void
+explicit_bzero(void *buf, size_t len)
+{
+#ifdef UB_ON_WINDOWS
+       SecureZeroMemory(buf, len);
+#endif
+       memset(buf, 0, len);
+       __explicit_bzero_hook(buf, len);
+}
diff --git a/compat/getentropy_linux.c b/compat/getentropy_linux.c
new file mode 100644 (file)
index 0000000..76f0f9d
--- /dev/null
@@ -0,0 +1,540 @@
+/*     $OpenBSD: getentropy_linux.c,v 1.20 2014/07/12 15:43:49 beck Exp $      */
+
+/*
+ * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org>
+ * Copyright (c) 2014 Bob Beck <beck@obtuse.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+/*
+#define        _POSIX_C_SOURCE 199309L
+#define        _GNU_SOURCE     1
+*/
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+#include <sys/statvfs.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <openssl/sha.h>
+
+#include <linux/types.h>
+#include <linux/random.h>
+#include <linux/sysctl.h>
+#ifdef HAVE_GETAUXVAL
+#include <sys/auxv.h>
+#endif
+#include <sys/vfs.h>
+
+#define REPEAT 5
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+#define HX(a, b) \
+       do { \
+               if ((a)) \
+                       HD(errno); \
+               else \
+                       HD(b); \
+       } while (0)
+
+#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
+#define HD(x)   (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
+#define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
+
+int    getentropy(void *buf, size_t len);
+
+#ifdef CAN_REFERENCE_MAIN
+extern int main(int, char *argv[]);
+#endif
+static int gotdata(char *buf, size_t len);
+#ifdef SYS_getrandom
+static int getentropy_getrandom(void *buf, size_t len);
+#endif
+static int getentropy_urandom(void *buf, size_t len);
+#ifdef SYS__sysctl
+static int getentropy_sysctl(void *buf, size_t len);
+#endif
+static int getentropy_fallback(void *buf, size_t len);
+
+int
+getentropy(void *buf, size_t len)
+{
+       int ret = -1;
+
+       if (len > 256) {
+               errno = EIO;
+               return -1;
+       }
+
+#ifdef SYS_getrandom
+       /*
+        * Try descriptor-less getrandom()
+        */
+       ret = getentropy_getrandom(buf, len);
+       if (ret != -1)
+               return (ret);
+       if (errno != ENOSYS)
+               return (-1);
+#endif
+
+       /*
+        * Try to get entropy with /dev/urandom
+        *
+        * This can fail if the process is inside a chroot or if file
+        * descriptors are exhausted.
+        */
+       ret = getentropy_urandom(buf, len);
+       if (ret != -1)
+               return (ret);
+
+#ifdef SYS__sysctl
+       /*
+        * Try to use sysctl CTL_KERN, KERN_RANDOM, RANDOM_UUID.
+        * sysctl is a failsafe API, so it guarantees a result.  This
+        * should work inside a chroot, or when file descriptors are
+        * exhuasted.
+        *
+        * However this can fail if the Linux kernel removes support
+        * for sysctl.  Starting in 2007, there have been efforts to
+        * deprecate the sysctl API/ABI, and push callers towards use
+        * of the chroot-unavailable fd-using /proc mechanism --
+        * essentially the same problems as /dev/urandom.
+        *
+        * Numerous setbacks have been encountered in their deprecation
+        * schedule, so as of June 2014 the kernel ABI still exists on
+        * most Linux architectures. The sysctl() stub in libc is missing
+        * on some systems.  There are also reports that some kernels
+        * spew messages to the console.
+        */
+       ret = getentropy_sysctl(buf, len);
+       if (ret != -1)
+               return (ret);
+#endif /* SYS__sysctl */
+
+       /*
+        * Entropy collection via /dev/urandom and sysctl have failed.
+        *
+        * No other API exists for collecting entropy.  See the large
+        * comment block above.
+        *
+        * We have very few options:
+        *     - Even syslog_r is unsafe to call at this low level, so
+        *       there is no way to alert the user or program.
+        *     - Cannot call abort() because some systems have unsafe
+        *       corefiles.
+        *     - Could raise(SIGKILL) resulting in silent program termination.
+        *     - Return EIO, to hint that arc4random's stir function
+        *       should raise(SIGKILL)
+        *     - Do the best under the circumstances....
+        *
+        * This code path exists to bring light to the issue that Linux
+        * does not provide a failsafe API for entropy collection.
+        *
+        * We hope this demonstrates that Linux should either retain their
+        * sysctl ABI, or consider providing a new failsafe API which
+        * works in a chroot or when file descriptors are exhausted.
+        */
+#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
+#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
+       raise(SIGKILL);
+#endif
+       ret = getentropy_fallback(buf, len);
+       if (ret != -1)
+               return (ret);
+
+       errno = EIO;
+       return (ret);
+}
+
+/*
+ * Basic sanity checking; wish we could do better.
+ */
+static int
+gotdata(char *buf, size_t len)
+{
+       char    any_set = 0;
+       size_t  i;
+
+       for (i = 0; i < len; ++i)
+               any_set |= buf[i];
+       if (any_set == 0)
+               return -1;
+       return 0;
+}
+
+#ifdef SYS_getrandom
+static int
+getentropy_getrandom(void *buf, size_t len)
+{
+       int pre_errno = errno;
+       int ret;
+       if (len > 256)
+               return (-1);
+       do {
+               ret = syscall(SYS_getrandom, buf, len, 0);
+       } while (ret == -1 && errno == EINTR);
+
+       if (ret != (int)len)
+               return (-1);
+       errno = pre_errno;
+       return (0);
+}
+#endif
+
+static int
+getentropy_urandom(void *buf, size_t len)
+{
+       struct stat st;
+       size_t i;
+       int fd, cnt, flags;
+       int save_errno = errno;
+
+start:
+
+       flags = O_RDONLY;
+#ifdef O_NOFOLLOW
+       flags |= O_NOFOLLOW;
+#endif
+#ifdef O_CLOEXEC
+       flags |= O_CLOEXEC;
+#endif
+       fd = open("/dev/urandom", flags, 0);
+       if (fd == -1) {
+               if (errno == EINTR)
+                       goto start;
+               goto nodevrandom;
+       }
+#ifndef O_CLOEXEC
+       fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+#endif
+
+       /* Lightly verify that the device node looks sane */
+       if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
+               close(fd);
+               goto nodevrandom;
+       }
+       if (ioctl(fd, RNDGETENTCNT, &cnt) == -1) {
+               close(fd);
+               goto nodevrandom;
+       }
+       for (i = 0; i < len; ) {
+               size_t wanted = len - i;
+               ssize_t ret = read(fd, (char*)buf + i, wanted);
+
+               if (ret == -1) {
+                       if (errno == EAGAIN || errno == EINTR)
+                               continue;
+                       close(fd);
+                       goto nodevrandom;
+               }
+               i += ret;
+       }
+       close(fd);
+       if (gotdata(buf, len) == 0) {
+               errno = save_errno;
+               return 0;               /* satisfied */
+       }
+nodevrandom:
+       errno = EIO;
+       return -1;
+}
+
+#ifdef SYS__sysctl
+static int
+getentropy_sysctl(void *buf, size_t len)
+{
+       static int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
+       size_t i;
+       int save_errno = errno;
+
+       for (i = 0; i < len; ) {
+               size_t chunk = min(len - i, 16);
+
+               /* SYS__sysctl because some systems already removed sysctl() */
+               struct __sysctl_args args = {
+                       .name = mib,
+                       .nlen = 3,
+                       .oldval = (char *)buf + i,
+                       .oldlenp = &chunk,
+               };
+               if (syscall(SYS__sysctl, &args) != 0)
+                       goto sysctlfailed;
+               i += chunk;
+       }
+       if (gotdata(buf, len) == 0) {
+               errno = save_errno;
+               return (0);                     /* satisfied */
+       }
+sysctlfailed:
+       errno = EIO;
+       return -1;
+}
+#endif /* SYS__sysctl */
+
+static int cl[] = {
+       CLOCK_REALTIME,
+#ifdef CLOCK_MONOTONIC
+       CLOCK_MONOTONIC,
+#endif
+#ifdef CLOCK_MONOTONIC_RAW
+       CLOCK_MONOTONIC_RAW,
+#endif
+#ifdef CLOCK_TAI
+       CLOCK_TAI,
+#endif
+#ifdef CLOCK_VIRTUAL
+       CLOCK_VIRTUAL,
+#endif
+#ifdef CLOCK_UPTIME
+       CLOCK_UPTIME,
+#endif
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+       CLOCK_PROCESS_CPUTIME_ID,
+#endif
+#ifdef CLOCK_THREAD_CPUTIME_ID
+       CLOCK_THREAD_CPUTIME_ID,
+#endif
+};
+
+static int
+getentropy_fallback(void *buf, size_t len)
+{
+       uint8_t results[SHA512_DIGEST_LENGTH];
+       int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
+       static int cnt;
+       struct timespec ts;
+       struct timeval tv;
+       struct rusage ru;
+       sigset_t sigset;
+       struct stat st;
+       SHA512_CTX ctx;
+       static pid_t lastpid;
+       pid_t pid;
+       size_t i, ii, m;
+       char *p;
+
+       pid = getpid();
+       if (lastpid == pid) {
+               faster = 1;
+               repeat = 2;
+       } else {
+               faster = 0;
+               lastpid = pid;
+               repeat = REPEAT;
+       }
+       for (i = 0; i < len; ) {
+               int j;
+               SHA512_Init(&ctx);
+               for (j = 0; j < repeat; j++) {
+                       HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+                       if (e != -1) {
+                               cnt += (int)tv.tv_sec;
+                               cnt += (int)tv.tv_usec;
+                       }
+
+                       for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++)
+                               HX(clock_gettime(cl[ii], &ts) == -1, ts);
+
+                       HX((pid = getpid()) == -1, pid);
+                       HX((pid = getsid(pid)) == -1, pid);
+                       HX((pid = getppid()) == -1, pid);
+                       HX((pid = getpgid(0)) == -1, pid);
+                       HX((e = getpriority(0, 0)) == -1, e);
+
+                       if (!faster) {
+                               ts.tv_sec = 0;
+                               ts.tv_nsec = 1;
+                               (void) nanosleep(&ts, NULL);
+                       }
+
+                       HX(sigpending(&sigset) == -1, sigset);
+                       HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
+                           sigset);
+
+#ifdef CAN_REFERENCE_MAIN
+                       HF(main);               /* an addr in program */
+#endif
+                       HF(getentropy); /* an addr in this library */
+                       HF(printf);             /* an addr in libc */
+                       p = (char *)&p;
+                       HD(p);          /* an addr on stack */
+                       p = (char *)&errno;
+                       HD(p);          /* the addr of errno */
+
+                       if (i == 0) {
+                               struct sockaddr_storage ss;
+                               struct statvfs stvfs;
+                               struct termios tios;
+                               struct statfs stfs;
+                               socklen_t ssl;
+                               off_t off;
+
+                               /*
+                                * Prime-sized mappings encourage fragmentation;
+                                * thus exposing some address entropy.
+                                */
+                               struct mm {
+                                       size_t  npg;
+                                       void    *p;
+                               } mm[] =         {
+                                       { 17, MAP_FAILED }, { 3, MAP_FAILED },
+                                       { 11, MAP_FAILED }, { 2, MAP_FAILED },
+                                       { 5, MAP_FAILED }, { 3, MAP_FAILED },
+                                       { 7, MAP_FAILED }, { 1, MAP_FAILED },
+                                       { 57, MAP_FAILED }, { 3, MAP_FAILED },
+                                       { 131, MAP_FAILED }, { 1, MAP_FAILED },
+                               };
+
+                               for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+                                       HX(mm[m].p = mmap(NULL,
+                                           mm[m].npg * pgs,
+                                           PROT_READ|PROT_WRITE,
+                                           MAP_PRIVATE|MAP_ANON, -1,
+                                           (off_t)0), mm[m].p);
+                                       if (mm[m].p != MAP_FAILED) {
+                                               size_t mo;
+
+                                               /* Touch some memory... */
+                                               p = mm[m].p;
+                                               mo = cnt %
+                                                   (mm[m].npg * pgs - 1);
+                                               p[mo] = 1;
+                                               cnt += (int)((long)(mm[m].p)
+                                                   / pgs);
+                                       }
+
+                                       /* Check cnts and times... */
+                                       for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]);
+                                           ii++) {
+                                               HX((e = clock_gettime(cl[ii],
+                                                   &ts)) == -1, ts);
+                                               if (e != -1)
+                                                       cnt += (int)ts.tv_nsec;
+                                       }
+
+                                       HX((e = getrusage(RUSAGE_SELF,
+                                           &ru)) == -1, ru);
+                                       if (e != -1) {
+                                               cnt += (int)ru.ru_utime.tv_sec;
+                                               cnt += (int)ru.ru_utime.tv_usec;
+                                       }
+                               }
+
+                               for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+                                       if (mm[m].p != MAP_FAILED)
+                                               munmap(mm[m].p, mm[m].npg * pgs);
+                                       mm[m].p = MAP_FAILED;
+                               }
+
+                               HX(stat(".", &st) == -1, st);
+                               HX(statvfs(".", &stvfs) == -1, stvfs);
+                               HX(statfs(".", &stfs) == -1, stfs);
+
+                               HX(stat("/", &st) == -1, st);
+                               HX(statvfs("/", &stvfs) == -1, stvfs);
+                               HX(statfs("/", &stfs) == -1, stfs);
+
+                               HX((e = fstat(0, &st)) == -1, st);
+                               if (e == -1) {
+                                       if (S_ISREG(st.st_mode) ||
+                                           S_ISFIFO(st.st_mode) ||
+                                           S_ISSOCK(st.st_mode)) {
+                                               HX(fstatvfs(0, &stvfs) == -1,
+                                                   stvfs);
+                                               HX(fstatfs(0, &stfs) == -1,
+                                                   stfs);
+                                               HX((off = lseek(0, (off_t)0,
+                                                   SEEK_CUR)) < 0, off);
+                                       }
+                                       if (S_ISCHR(st.st_mode)) {
+                                               HX(tcgetattr(0, &tios) == -1,
+                                                   tios);
+                                       } else if (S_ISSOCK(st.st_mode)) {
+                                               memset(&ss, 0, sizeof ss);
+                                               ssl = sizeof(ss);
+                                               HX(getpeername(0,
+                                                   (void *)&ss, &ssl) == -1,
+                                                   ss);
+                                       }
+                               }
+
+                               HX((e = getrusage(RUSAGE_CHILDREN,
+                                   &ru)) == -1, ru);
+                               if (e != -1) {
+                                       cnt += (int)ru.ru_utime.tv_sec;
+                                       cnt += (int)ru.ru_utime.tv_usec;
+                               }
+                       } else {
+                               /* Subsequent hashes absorb previous result */
+                               HD(results);
+                       }
+
+                       HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+                       if (e != -1) {
+                               cnt += (int)tv.tv_sec;
+                               cnt += (int)tv.tv_usec;
+                       }
+
+                       HD(cnt);
+               }
+#ifdef HAVE_GETAUXVAL
+#  ifdef AT_RANDOM
+               /* Not as random as you think but we take what we are given */
+               p = (char *) getauxval(AT_RANDOM);
+               if (p)
+                       HR(p, 16);
+#  endif
+#  ifdef AT_SYSINFO_EHDR
+               p = (char *) getauxval(AT_SYSINFO_EHDR);
+               if (p)
+                       HR(p, pgs);
+#  endif
+#  ifdef AT_BASE
+               p = (char *) getauxval(AT_BASE);
+               if (p)
+                       HD(p);
+#  endif
+#endif /* HAVE_GETAUXVAL */
+
+               SHA512_Final(results, &ctx);
+               memcpy((char*)buf + i, results, min(sizeof(results), len - i));
+               i += min(sizeof(results), len - i);
+       }
+       memset(results, 0, sizeof results);
+       if (gotdata(buf, len) == 0) {
+               errno = save_errno;
+               return 0;               /* satisfied */
+       }
+       errno = EIO;
+       return -1;
+}
diff --git a/compat/getentropy_osx.c b/compat/getentropy_osx.c
new file mode 100644 (file)
index 0000000..d5a64ab
--- /dev/null
@@ -0,0 +1,432 @@
+/*     $OpenBSD: getentropy_osx.c,v 1.3 2014/07/12 14:48:00 deraadt Exp $      */
+
+/*
+ * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org>
+ * Copyright (c) 2014 Bob Beck <beck@obtuse.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/sysctl.h>
+#include <sys/statvfs.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <mach/mach_time.h>
+#include <mach/mach_host.h>
+#include <mach/host_info.h>
+#include <sys/socketvar.h>
+#include <sys/vmmeter.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp_var.h>
+#include <netinet/udp_var.h>
+#include <CommonCrypto/CommonDigest.h>
+#define SHA512_Update(a, b, c) (CC_SHA512_Update((a), (b), (c)))
+#define SHA512_Init(xxx) (CC_SHA512_Init((xxx)))
+#define SHA512_Final(xxx, yyy) (CC_SHA512_Final((xxx), (yyy)))
+#define SHA512_CTX CC_SHA512_CTX
+#define SHA512_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH
+
+#define REPEAT 5
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+#define HX(a, b) \
+       do { \
+               if ((a)) \
+                       HD(errno); \
+               else \
+                       HD(b); \
+       } while (0)
+
+#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
+#define HD(x)   (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
+#define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
+
+int    getentropy(void *buf, size_t len);
+
+#ifdef CAN_REFERENCE_MAIN
+extern int main(int, char *argv[]);
+#endif
+static int gotdata(char *buf, size_t len);
+static int getentropy_urandom(void *buf, size_t len);
+static int getentropy_fallback(void *buf, size_t len);
+
+int
+getentropy(void *buf, size_t len)
+{
+       int ret = -1;
+
+       if (len > 256) {
+               errno = EIO;
+               return -1;
+       }
+
+       /*
+        * Try to get entropy with /dev/urandom
+        *
+        * This can fail if the process is inside a chroot or if file
+        * descriptors are exhausted.
+        */
+       ret = getentropy_urandom(buf, len);
+       if (ret != -1)
+               return (ret);
+
+       /*
+        * Entropy collection via /dev/urandom and sysctl have failed.
+        *
+        * No other API exists for collecting entropy, and we have
+        * no failsafe way to get it on OSX that is not sensitive
+        * to resource exhaustion.
+        *
+        * We have very few options:
+        *     - Even syslog_r is unsafe to call at this low level, so
+        *       there is no way to alert the user or program.
+        *     - Cannot call abort() because some systems have unsafe
+        *       corefiles.
+        *     - Could raise(SIGKILL) resulting in silent program termination.
+        *     - Return EIO, to hint that arc4random's stir function
+        *       should raise(SIGKILL)
+        *     - Do the best under the circumstances....
+        *
+        * This code path exists to bring light to the issue that OSX
+        * does not provide a failsafe API for entropy collection.
+        *
+        * We hope this demonstrates that OSX should consider
+        * providing a new failsafe API which works in a chroot or
+        * when file descriptors are exhausted.
+        */
+#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
+#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
+       raise(SIGKILL);
+#endif
+       ret = getentropy_fallback(buf, len);
+       if (ret != -1)
+               return (ret);
+
+       errno = EIO;
+       return (ret);
+}
+
+/*
+ * Basic sanity checking; wish we could do better.
+ */
+static int
+gotdata(char *buf, size_t len)
+{
+       char    any_set = 0;
+       size_t  i;
+
+       for (i = 0; i < len; ++i)
+               any_set |= buf[i];
+       if (any_set == 0)
+               return -1;
+       return 0;
+}
+
+static int
+getentropy_urandom(void *buf, size_t len)
+{
+       struct stat st;
+       size_t i;
+       int fd, flags;
+       int save_errno = errno;
+
+start:
+
+       flags = O_RDONLY;
+#ifdef O_NOFOLLOW
+       flags |= O_NOFOLLOW;
+#endif
+#ifdef O_CLOEXEC
+       flags |= O_CLOEXEC;
+#endif
+       fd = open("/dev/urandom", flags, 0);
+       if (fd == -1) {
+               if (errno == EINTR)
+                       goto start;
+               goto nodevrandom;
+       }
+#ifndef O_CLOEXEC
+       fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+#endif
+
+       /* Lightly verify that the device node looks sane */
+       if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
+               close(fd);
+               goto nodevrandom;
+       }
+       for (i = 0; i < len; ) {
+               size_t wanted = len - i;
+               ssize_t ret = read(fd, (char*)buf + i, wanted);
+
+               if (ret == -1) {
+                       if (errno == EAGAIN || errno == EINTR)
+                               continue;
+                       close(fd);
+                       goto nodevrandom;
+               }
+               i += ret;
+       }
+       close(fd);
+       if (gotdata(buf, len) == 0) {
+               errno = save_errno;
+               return 0;               /* satisfied */
+       }
+nodevrandom:
+       errno = EIO;
+       return -1;
+}
+
+static int tcpmib[] = { CTL_NET, AF_INET, IPPROTO_TCP, TCPCTL_STATS };
+static int udpmib[] = { CTL_NET, AF_INET, IPPROTO_UDP, UDPCTL_STATS };
+static int ipmib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_STATS };
+static int kmib[] = { CTL_KERN, KERN_USRSTACK };
+static int hwmib[] = { CTL_HW, HW_USERMEM };
+
+static int
+getentropy_fallback(void *buf, size_t len)
+{
+       uint8_t results[SHA512_DIGEST_LENGTH];
+       int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
+       static int cnt;
+       struct timespec ts;
+       struct timeval tv;
+       struct rusage ru;
+       sigset_t sigset;
+       struct stat st;
+       SHA512_CTX ctx;
+       static pid_t lastpid;
+       pid_t pid;
+       size_t i, ii, m;
+       char *p;
+       struct tcpstat tcpstat;
+       struct udpstat udpstat;
+       struct ipstat ipstat;
+       u_int64_t mach_time;
+       unsigned int idata;
+       void *addr;
+
+       pid = getpid();
+       if (lastpid == pid) {
+               faster = 1;
+               repeat = 2;
+       } else {
+               faster = 0;
+               lastpid = pid;
+               repeat = REPEAT;
+       }
+       for (i = 0; i < len; ) {
+               int j;
+               SHA512_Init(&ctx);
+               for (j = 0; j < repeat; j++) {
+                       HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+                       if (e != -1) {
+                               cnt += (int)tv.tv_sec;
+                               cnt += (int)tv.tv_usec;
+                       }
+
+                       mach_time = mach_absolute_time();
+                       HD(mach_time);
+
+                       ii = sizeof(addr);
+                       HX(sysctl(kmib, sizeof(kmib) / sizeof(kmib[0]),
+                           &addr, &ii, NULL, 0) == -1, addr);
+
+                       ii = sizeof(idata);
+                       HX(sysctl(hwmib, sizeof(hwmib) / sizeof(hwmib[0]),
+                           &idata, &ii, NULL, 0) == -1, idata);
+
+                       ii = sizeof(tcpstat);
+                       HX(sysctl(tcpmib, sizeof(tcpmib) / sizeof(tcpmib[0]),
+                           &tcpstat, &ii, NULL, 0) == -1, tcpstat);
+
+                       ii = sizeof(udpstat);
+                       HX(sysctl(udpmib, sizeof(udpmib) / sizeof(udpmib[0]),
+                           &udpstat, &ii, NULL, 0) == -1, udpstat);
+
+                       ii = sizeof(ipstat);
+                       HX(sysctl(ipmib, sizeof(ipmib) / sizeof(ipmib[0]),
+                           &ipstat, &ii, NULL, 0) == -1, ipstat);
+
+                       HX((pid = getpid()) == -1, pid);
+                       HX((pid = getsid(pid)) == -1, pid);
+                       HX((pid = getppid()) == -1, pid);
+                       HX((pid = getpgid(0)) == -1, pid);
+                       HX((e = getpriority(0, 0)) == -1, e);
+
+                       if (!faster) {
+                               ts.tv_sec = 0;
+                               ts.tv_nsec = 1;
+                               (void) nanosleep(&ts, NULL);
+                       }
+
+                       HX(sigpending(&sigset) == -1, sigset);
+                       HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
+                           sigset);
+
+#ifdef CAN_REFERENCE_MAIN
+                       HF(main);               /* an addr in program */
+#endif
+                       HF(getentropy); /* an addr in this library */
+                       HF(printf);             /* an addr in libc */
+                       p = (char *)&p;
+                       HD(p);          /* an addr on stack */
+                       p = (char *)&errno;
+                       HD(p);          /* the addr of errno */
+
+                       if (i == 0) {
+                               struct sockaddr_storage ss;
+                               struct statvfs stvfs;
+                               struct termios tios;
+                               struct statfs stfs;
+                               socklen_t ssl;
+                               off_t off;
+
+                               /*
+                                * Prime-sized mappings encourage fragmentation;
+                                * thus exposing some address entropy.
+                                */
+                               struct mm {
+                                       size_t  npg;
+                                       void    *p;
+                               } mm[] =         {
+                                       { 17, MAP_FAILED }, { 3, MAP_FAILED },
+                                       { 11, MAP_FAILED }, { 2, MAP_FAILED },
+                                       { 5, MAP_FAILED }, { 3, MAP_FAILED },
+                                       { 7, MAP_FAILED }, { 1, MAP_FAILED },
+                                       { 57, MAP_FAILED }, { 3, MAP_FAILED },
+                                       { 131, MAP_FAILED }, { 1, MAP_FAILED },
+                               };
+
+                               for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+                                       HX(mm[m].p = mmap(NULL,
+                                           mm[m].npg * pgs,
+                                           PROT_READ|PROT_WRITE,
+                                           MAP_PRIVATE|MAP_ANON, -1,
+                                           (off_t)0), mm[m].p);
+                                       if (mm[m].p != MAP_FAILED) {
+                                               size_t mo;
+
+                                               /* Touch some memory... */
+                                               p = mm[m].p;
+                                               mo = cnt %
+                                                   (mm[m].npg * pgs - 1);
+                                               p[mo] = 1;
+                                               cnt += (int)((long)(mm[m].p)
+                                                   / pgs);
+                                       }
+
+                                       /* Check cnts and times... */
+                                       mach_time = mach_absolute_time();
+                                       HD(mach_time);
+                                       cnt += (int)mach_time;
+
+                                       HX((e = getrusage(RUSAGE_SELF,
+                                           &ru)) == -1, ru);
+                                       if (e != -1) {
+                                               cnt += (int)ru.ru_utime.tv_sec;
+                                               cnt += (int)ru.ru_utime.tv_usec;
+                                       }
+                               }
+
+                               for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+                                       if (mm[m].p != MAP_FAILED)
+                                               munmap(mm[m].p, mm[m].npg * pgs);
+                                       mm[m].p = MAP_FAILED;
+                               }
+
+                               HX(stat(".", &st) == -1, st);
+                               HX(statvfs(".", &stvfs) == -1, stvfs);
+                               HX(statfs(".", &stfs) == -1, stfs);
+
+                               HX(stat("/", &st) == -1, st);
+                               HX(statvfs("/", &stvfs) == -1, stvfs);
+                               HX(statfs("/", &stfs) == -1, stfs);
+
+                               HX((e = fstat(0, &st)) == -1, st);
+                               if (e == -1) {
+                                       if (S_ISREG(st.st_mode) ||
+                                           S_ISFIFO(st.st_mode) ||
+                                           S_ISSOCK(st.st_mode)) {
+                                               HX(fstatvfs(0, &stvfs) == -1,
+                                                   stvfs);
+                                               HX(fstatfs(0, &stfs) == -1,
+                                                   stfs);
+                                               HX((off = lseek(0, (off_t)0,
+                                                   SEEK_CUR)) < 0, off);
+                                       }
+                                       if (S_ISCHR(st.st_mode)) {
+                                               HX(tcgetattr(0, &tios) == -1,
+                                                   tios);
+                                       } else if (S_ISSOCK(st.st_mode)) {
+                                               memset(&ss, 0, sizeof ss);
+                                               ssl = sizeof(ss);
+                                               HX(getpeername(0,
+                                                   (void *)&ss, &ssl) == -1,
+                                                   ss);
+                                       }
+                               }
+
+                               HX((e = getrusage(RUSAGE_CHILDREN,
+                                   &ru)) == -1, ru);
+                               if (e != -1) {
+                                       cnt += (int)ru.ru_utime.tv_sec;
+                                       cnt += (int)ru.ru_utime.tv_usec;
+                               }
+                       } else {
+                               /* Subsequent hashes absorb previous result */
+                               HD(results);
+                       }
+
+                       HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+                       if (e != -1) {
+                               cnt += (int)tv.tv_sec;
+                               cnt += (int)tv.tv_usec;
+                       }
+
+                       HD(cnt);
+               }
+
+               SHA512_Final(results, &ctx);
+               memcpy((char*)buf + i, results, min(sizeof(results), len - i));
+               i += min(sizeof(results), len - i);
+       }
+       memset(results, 0, sizeof results);
+       if (gotdata(buf, len) == 0) {
+               errno = save_errno;
+               return 0;               /* satisfied */
+       }
+       errno = EIO;
+       return -1;
+}
diff --git a/compat/getentropy_solaris.c b/compat/getentropy_solaris.c
new file mode 100644 (file)
index 0000000..8389573
--- /dev/null
@@ -0,0 +1,435 @@
+/*     $OpenBSD: getentropy_solaris.c,v 1.3 2014/07/12 14:46:31 deraadt Exp $  */
+
+/*
+ * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org>
+ * Copyright (c) 2014 Bob Beck <beck@obtuse.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/statvfs.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/sha2.h>
+#define SHA512_Init SHA512Init
+#define SHA512_Update SHA512Update
+#define SHA512_Final SHA512Final
+
+#include <sys/vfs.h>
+#include <sys/statfs.h>
+#include <sys/loadavg.h>
+
+#define REPEAT 5
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+#define HX(a, b) \
+       do { \
+               if ((a)) \
+                       HD(errno); \
+               else \
+                       HD(b); \
+       } while (0)
+
+#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
+#define HD(x)   (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
+#define HF(x)   (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
+
+int    getentropy(void *buf, size_t len);
+
+#ifdef CAN_REFERENCE_MAIN
+extern int main(int, char *argv[]);
+#endif
+static int gotdata(char *buf, size_t len);
+static int getentropy_urandom(void *buf, size_t len, const char *path,
+    int devfscheck);
+static int getentropy_fallback(void *buf, size_t len);
+
+int
+getentropy(void *buf, size_t len)
+{
+       int ret = -1;
+
+       if (len > 256) {
+               errno = EIO;
+               return -1;
+       }
+
+       /*
+        * Try to get entropy with /dev/urandom
+        *
+        * Solaris provides /dev/urandom as a symbolic link to
+        * /devices/pseudo/random@0:urandom which is provided by
+        * a devfs filesystem.  Best practice is to use O_NOFOLLOW,
+        * so we must try the unpublished name directly.
+        *
+        * This can fail if the process is inside a chroot which lacks
+        * the devfs mount, or if file descriptors are exhausted.
+        */
+       ret = getentropy_urandom(buf, len,
+           "/devices/pseudo/random@0:urandom", 1);
+       if (ret != -1)
+               return (ret);
+
+       /*
+        * Unfortunately, chroot spaces on Solaris are sometimes setup
+        * with direct device node of the well-known /dev/urandom name
+        * (perhaps to avoid dragging all of devfs into the space).
+        *
+        * This can fail if the process is inside a chroot or if file
+        * descriptors are exhausted.
+        */
+       ret = getentropy_urandom(buf, len, "/dev/urandom", 0);
+       if (ret != -1)
+               return (ret);
+
+       /*
+        * Entropy collection via /dev/urandom has failed.
+        *
+        * No other API exists for collecting entropy, and we have
+        * no failsafe way to get it on Solaris that is not sensitive
+        * to resource exhaustion.
+        *
+        * We have very few options:
+        *     - Even syslog_r is unsafe to call at this low level, so
+        *       there is no way to alert the user or program.
+        *     - Cannot call abort() because some systems have unsafe
+        *       corefiles.
+        *     - Could raise(SIGKILL) resulting in silent program termination.
+        *     - Return EIO, to hint that arc4random's stir function
+        *       should raise(SIGKILL)
+        *     - Do the best under the circumstances....
+        *
+        * This code path exists to bring light to the issue that Solaris
+        * does not provide a failsafe API for entropy collection.
+        *
+        * We hope this demonstrates that Solaris should consider
+        * providing a new failsafe API which works in a chroot or
+        * when file descriptors are exhausted.
+        */
+#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
+#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
+       raise(SIGKILL);
+#endif
+       ret = getentropy_fallback(buf, len);
+       if (ret != -1)
+               return (ret);
+
+       errno = EIO;
+       return (ret);
+}
+
+/*
+ * Basic sanity checking; wish we could do better.
+ */
+static int
+gotdata(char *buf, size_t len)
+{
+       char    any_set = 0;
+       size_t  i;
+
+       for (i = 0; i < len; ++i)
+               any_set |= buf[i];
+       if (any_set == 0)
+               return -1;
+       return 0;
+}
+
+static int
+getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck)
+{
+       struct stat st;
+       size_t i;
+       int fd, flags;
+       int save_errno = errno;
+
+start:
+
+       flags = O_RDONLY;
+#ifdef O_NOFOLLOW
+       flags |= O_NOFOLLOW;
+#endif
+#ifdef O_CLOEXEC
+       flags |= O_CLOEXEC;
+#endif
+       fd = open(path, flags, 0);
+       if (fd == -1) {
+               if (errno == EINTR)
+                       goto start;
+               goto nodevrandom;
+       }
+#ifndef O_CLOEXEC
+       fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+#endif
+
+       /* Lightly verify that the device node looks sane */
+       if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode) ||
+           (devfscheck && (strcmp(st.st_fstype, "devfs") != 0))) {
+               close(fd);
+               goto nodevrandom;
+       }
+       for (i = 0; i < len; ) {
+               size_t wanted = len - i;
+               ssize_t ret = read(fd, (char*)buf + i, wanted);
+
+               if (ret == -1) {
+                       if (errno == EAGAIN || errno == EINTR)
+                               continue;
+                       close(fd);
+                       goto nodevrandom;
+               }
+               i += ret;
+       }
+       close(fd);
+       if (gotdata(buf, len) == 0) {
+               errno = save_errno;
+               return 0;               /* satisfied */
+       }
+nodevrandom:
+       errno = EIO;
+       return -1;
+}
+
+static const int cl[] = {
+       CLOCK_REALTIME,
+#ifdef CLOCK_MONOTONIC
+       CLOCK_MONOTONIC,
+#endif
+#ifdef CLOCK_MONOTONIC_RAW
+       CLOCK_MONOTONIC_RAW,
+#endif
+#ifdef CLOCK_TAI
+       CLOCK_TAI,
+#endif
+#ifdef CLOCK_VIRTUAL
+       CLOCK_VIRTUAL,
+#endif
+#ifdef CLOCK_UPTIME
+       CLOCK_UPTIME,
+#endif
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+       CLOCK_PROCESS_CPUTIME_ID,
+#endif
+#ifdef CLOCK_THREAD_CPUTIME_ID
+       CLOCK_THREAD_CPUTIME_ID,
+#endif
+};
+
+static int
+getentropy_fallback(void *buf, size_t len)
+{
+       uint8_t results[SHA512_DIGEST_LENGTH];
+       int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
+       static int cnt;
+       struct timespec ts;
+       struct timeval tv;
+       double loadavg[3];
+       struct rusage ru;
+       sigset_t sigset;
+       struct stat st;
+       SHA512_CTX ctx;
+       static pid_t lastpid;
+       pid_t pid;
+       size_t i, ii, m;
+       char *p;
+
+       pid = getpid();
+       if (lastpid == pid) {
+               faster = 1;
+               repeat = 2;
+       } else {
+               faster = 0;
+               lastpid = pid;
+               repeat = REPEAT;
+       }
+       for (i = 0; i < len; ) {
+               int j;
+               SHA512_Init(&ctx);
+               for (j = 0; j < repeat; j++) {
+                       HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+                       if (e != -1) {
+                               cnt += (int)tv.tv_sec;
+                               cnt += (int)tv.tv_usec;
+                       }
+
+                       for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++)
+                               HX(clock_gettime(cl[ii], &ts) == -1, ts);
+
+                       HX((pid = getpid()) == -1, pid);
+                       HX((pid = getsid(pid)) == -1, pid);
+                       HX((pid = getppid()) == -1, pid);
+                       HX((pid = getpgid(0)) == -1, pid);
+                       HX((e = getpriority(0, 0)) == -1, e);
+                       HX((getloadavg(loadavg, 3) == -1), loadavg);
+
+                       if (!faster) {
+                               ts.tv_sec = 0;
+                               ts.tv_nsec = 1;
+                               (void) nanosleep(&ts, NULL);
+                       }
+
+                       HX(sigpending(&sigset) == -1, sigset);
+                       HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
+                           sigset);
+
+#ifdef CAN_REFERENCE_MAIN
+                       HF(main);               /* an addr in program */
+#endif
+                       HF(getentropy); /* an addr in this library */
+                       HF(printf);             /* an addr in libc */
+                       p = (char *)&p;
+                       HD(p);          /* an addr on stack */
+                       p = (char *)&errno;
+                       HD(p);          /* the addr of errno */
+
+                       if (i == 0) {
+                               struct sockaddr_storage ss;
+                               struct statvfs stvfs;
+                               struct termios tios;
+                               socklen_t ssl;
+                               off_t off;
+
+                               /*
+                                * Prime-sized mappings encourage fragmentation;
+                                * thus exposing some address entropy.
+                                */
+                               struct mm {
+                                       size_t  npg;
+                                       void    *p;
+                               } mm[] =         {
+                                       { 17, MAP_FAILED }, { 3, MAP_FAILED },
+                                       { 11, MAP_FAILED }, { 2, MAP_FAILED },
+                                       { 5, MAP_FAILED }, { 3, MAP_FAILED },
+                                       { 7, MAP_FAILED }, { 1, MAP_FAILED },
+                                       { 57, MAP_FAILED }, { 3, MAP_FAILED },
+                                       { 131, MAP_FAILED }, { 1, MAP_FAILED },
+                               };
+
+                               for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+                                       HX(mm[m].p = mmap(NULL,
+                                           mm[m].npg * pgs,
+                                           PROT_READ|PROT_WRITE,
+                                           MAP_PRIVATE|MAP_ANON, -1,
+                                           (off_t)0), mm[m].p);
+                                       if (mm[m].p != MAP_FAILED) {
+                                               size_t mo;
+
+                                               /* Touch some memory... */
+                                               p = mm[m].p;
+                                               mo = cnt %
+                                                   (mm[m].npg * pgs - 1);
+                                               p[mo] = 1;
+                                               cnt += (int)((long)(mm[m].p)
+                                                   / pgs);
+                                       }
+
+                                       /* Check cnts and times... */
+                                       for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]);
+                                           ii++) {
+                                               HX((e = clock_gettime(cl[ii],
+                                                   &ts)) == -1, ts);
+                                               if (e != -1)
+                                                       cnt += (int)ts.tv_nsec;
+                                       }
+
+                                       HX((e = getrusage(RUSAGE_SELF,
+                                           &ru)) == -1, ru);
+                                       if (e != -1) {
+                                               cnt += (int)ru.ru_utime.tv_sec;
+                                               cnt += (int)ru.ru_utime.tv_usec;
+                                       }
+                               }
+
+                               for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
+                                       if (mm[m].p != MAP_FAILED)
+                                               munmap(mm[m].p, mm[m].npg * pgs);
+                                       mm[m].p = MAP_FAILED;
+                               }
+
+                               HX(stat(".", &st) == -1, st);
+                               HX(statvfs(".", &stvfs) == -1, stvfs);
+
+                               HX(stat("/", &st) == -1, st);
+                               HX(statvfs("/", &stvfs) == -1, stvfs);
+
+                               HX((e = fstat(0, &st)) == -1, st);
+                               if (e == -1) {
+                                       if (S_ISREG(st.st_mode) ||
+                                           S_ISFIFO(st.st_mode) ||
+                                           S_ISSOCK(st.st_mode)) {
+                                               HX(fstatvfs(0, &stvfs) == -1,
+                                                   stvfs);
+                                               HX((off = lseek(0, (off_t)0,
+                                                   SEEK_CUR)) < 0, off);
+                                       }
+                                       if (S_ISCHR(st.st_mode)) {
+                                               HX(tcgetattr(0, &tios) == -1,
+                                                   tios);
+                                       } else if (S_ISSOCK(st.st_mode)) {
+                                               memset(&ss, 0, sizeof ss);
+                                               ssl = sizeof(ss);
+                                               HX(getpeername(0,
+                                                   (void *)&ss, &ssl) == -1,
+                                                   ss);
+                                       }
+                               }
+
+                               HX((e = getrusage(RUSAGE_CHILDREN,
+                                   &ru)) == -1, ru);
+                               if (e != -1) {
+                                       cnt += (int)ru.ru_utime.tv_sec;
+                                       cnt += (int)ru.ru_utime.tv_usec;
+                               }
+                       } else {
+                               /* Subsequent hashes absorb previous result */
+                               HD(results);
+                       }
+
+                       HX((e = gettimeofday(&tv, NULL)) == -1, tv);
+                       if (e != -1) {
+                               cnt += (int)tv.tv_sec;
+                               cnt += (int)tv.tv_usec;
+                       }
+
+                       HD(cnt);
+               }
+               SHA512_Final(results, &ctx);
+               memcpy((char*)buf + i, results, min(sizeof(results), len - i));
+               i += min(sizeof(results), len - i);
+       }
+       memset(results, 0, sizeof results);
+       if (gotdata(buf, len) == 0) {
+               errno = save_errno;
+               return 0;               /* satisfied */
+       }
+       errno = EIO;
+       return -1;
+}
diff --git a/compat/getentropy_win.c b/compat/getentropy_win.c
new file mode 100644 (file)
index 0000000..71fb955
--- /dev/null
@@ -0,0 +1,56 @@
+/*     $OpenBSD$       */
+
+/*
+ * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org> 
+ * Copyright (c) 2014, Bob Beck <beck@obtuse.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <windows.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <wincrypt.h>
+#include <process.h>
+
+int    getentropy(void *buf, size_t len);
+
+/*
+ * On Windows, CryptGenRandom is supposed to be a well-seeded
+ * cryptographically strong random number generator.
+ */
+int
+getentropy(void *buf, size_t len)
+{
+       HCRYPTPROV provider;
+
+       if (len > 256) {
+               errno = EIO;
+               return -1;
+       }
+
+       if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
+           CRYPT_VERIFYCONTEXT) == 0)
+               goto fail;
+       if (CryptGenRandom(provider, len, buf) == 0) {
+               CryptReleaseContext(provider, 0);
+               goto fail;
+       }
+       CryptReleaseContext(provider, 0);
+       return (0);
+
+fail:
+       errno = EIO;
+       return (-1);
+}
diff --git a/compat/reallocarray.c b/compat/reallocarray.c
new file mode 100644 (file)
index 0000000..04d5d71
--- /dev/null
@@ -0,0 +1,39 @@
+/*     $OpenBSD: reallocarray.c,v 1.1 2014/05/08 21:43:49 deraadt Exp $        */
+/*
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+#include <sys/types.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW        ((size_t)1 << (sizeof(size_t) * 4))
+
+void *
+reallocarray(void *optr, size_t nmemb, size_t size)
+{
+       if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+           nmemb > 0 && SIZE_MAX / nmemb < size) {
+               errno = ENOMEM;
+               return NULL;
+       }
+       return realloc(optr, size * nmemb);
+}
diff --git a/compat/sha512.c b/compat/sha512.c
new file mode 100644 (file)
index 0000000..ac046ab
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ * FILE:       sha2.c
+ * AUTHOR:     Aaron D. Gifford - http://www.aarongifford.com/
+ * 
+ * Copyright (c) 2000-2001, Aaron D. Gifford
+ * All rights reserved.
+ *
+ * Modified by Jelte Jansen to fit in ldns, and not clash with any
+ * system-defined SHA code.
+ * Changes:
+ * - Renamed (external) functions and constants to fit ldns style
+ * - Removed _End and _Data functions
+ * - Added ldns_shaX(data, len, digest) convenience functions
+ * - Removed prototypes of _Transform functions and made those static
+ * Modified by Wouter, and trimmed, to provide SHA512 for getentropy_fallback.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $
+ */
+#include "config.h"
+
+#include <string.h>    /* memcpy()/memset() or bcopy()/bzero() */
+#include <assert.h>    /* assert() */
+
+/* do we have sha512 header defs */
+#ifndef SHA512_DIGEST_LENGTH
+#define SHA512_BLOCK_LENGTH            128
+#define SHA512_DIGEST_LENGTH           64
+#define SHA512_DIGEST_STRING_LENGTH    (SHA512_DIGEST_LENGTH * 2 + 1)
+typedef struct _SHA512_CTX {
+       uint64_t        state[8];
+       uint64_t        bitcount[2];
+       uint8_t buffer[SHA512_BLOCK_LENGTH];
+} SHA512_CTX;
+#endif /* do we have sha512 header defs */
+
+void SHA512_Init(SHA512_CTX*);
+void SHA512_Update(SHA512_CTX*, void*, size_t);
+void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*);
+unsigned char *SHA512(void *data, unsigned int data_len, unsigned char *digest);
+
+
+/*** SHA-256/384/512 Machine Architecture Definitions *****************/
+/*
+ * BYTE_ORDER NOTE:
+ *
+ * Please make sure that your system defines BYTE_ORDER.  If your
+ * architecture is little-endian, make sure it also defines
+ * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
+ * equivilent.
+ *
+ * If your system does not define the above, then you can do so by
+ * hand like this:
+ *
+ *   #define LITTLE_ENDIAN 1234
+ *   #define BIG_ENDIAN    4321
+ *
+ * And for little-endian machines, add:
+ *
+ *   #define BYTE_ORDER LITTLE_ENDIAN 
+ *
+ * Or for big-endian machines:
+ *
+ *   #define BYTE_ORDER BIG_ENDIAN
+ *
+ * The FreeBSD machine this was written on defines BYTE_ORDER
+ * appropriately by including <sys/types.h> (which in turn includes
+ * <machine/endian.h> where the appropriate definitions are actually
+ * made).
+ */
+#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN)
+#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN
+#endif
+
+typedef uint8_t  sha2_byte;    /* Exactly 1 byte */
+typedef uint32_t sha2_word32;  /* Exactly 4 bytes */
+#ifdef S_SPLINT_S
+typedef unsigned long long sha2_word64; /* lint 8 bytes */
+#else
+typedef uint64_t sha2_word64;  /* Exactly 8 bytes */
+#endif
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+#define SHA512_SHORT_BLOCK_LENGTH      (SHA512_BLOCK_LENGTH - 16)
+
+
+/*** ENDIAN REVERSAL MACROS *******************************************/
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define REVERSE32(w,x) { \
+       sha2_word32 tmp = (w); \
+       tmp = (tmp >> 16) | (tmp << 16); \
+       (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
+}
+#ifndef S_SPLINT_S
+#define REVERSE64(w,x) { \
+       sha2_word64 tmp = (w); \
+       tmp = (tmp >> 32) | (tmp << 32); \
+       tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
+             ((tmp & 0x00ff00ff00ff00ffULL) << 8); \
+       (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
+             ((tmp & 0x0000ffff0000ffffULL) << 16); \
+}
+#else /* splint */
+#define REVERSE64(w,x) /* splint */
+#endif /* splint */
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+/*
+ * Macro for incrementally adding the unsigned 64-bit integer n to the
+ * unsigned 128-bit integer (represented using a two-element array of
+ * 64-bit words):
+ */
+#define ADDINC128(w,n) { \
+       (w)[0] += (sha2_word64)(n); \
+       if ((w)[0] < (n)) { \
+               (w)[1]++; \
+       } \
+}
+#ifdef S_SPLINT_S
+#undef ADDINC128
+#define ADDINC128(w,n) /* splint */
+#endif
+
+/*
+ * Macros for copying blocks of memory and for zeroing out ranges
+ * of memory.  Using these macros makes it easy to switch from
+ * using memset()/memcpy() and using bzero()/bcopy().
+ *
+ * Please define either SHA2_USE_MEMSET_MEMCPY or define
+ * SHA2_USE_BZERO_BCOPY depending on which function set you
+ * choose to use:
+ */
+#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY)
+/* Default to memset()/memcpy() if no option is specified */
+#define        SHA2_USE_MEMSET_MEMCPY  1
+#endif
+#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY)
+/* Abort with an error if BOTH options are defined */
+#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both!
+#endif
+
+#ifdef SHA2_USE_MEMSET_MEMCPY
+#define MEMSET_BZERO(p,l)      memset((p), 0, (l))
+#define MEMCPY_BCOPY(d,s,l)    memcpy((d), (s), (l))
+#endif
+#ifdef SHA2_USE_BZERO_BCOPY
+#define MEMSET_BZERO(p,l)      bzero((p), (l))
+#define MEMCPY_BCOPY(d,s,l)    bcopy((s), (d), (l))
+#endif
+
+
+/*** THE SIX LOGICAL FUNCTIONS ****************************************/
+/*
+ * Bit shifting and rotation (used by the six SHA-XYZ logical functions:
+ *
+ *   NOTE:  The naming of R and S appears backwards here (R is a SHIFT and
+ *   S is a ROTATION) because the SHA-256/384/512 description document
+ *   (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
+ *   same "backwards" definition.
+ */
+/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
+#define R(b,x)                 ((x) >> (b))
+/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
+#define S64(b,x)       (((x) >> (b)) | ((x) << (64 - (b))))
+
+/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
+#define Ch(x,y,z)      (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z)     (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+/* Four of six logical functions used in SHA-384 and SHA-512: */
+#define Sigma0_512(x)  (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
+#define Sigma1_512(x)  (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
+#define sigma0_512(x)  (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7,   (x)))
+#define sigma1_512(x)  (S64(19, (x)) ^ S64(61, (x)) ^ R( 6,   (x)))
+
+/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
+/* Hash constant words K for SHA-384 and SHA-512: */
+static const sha2_word64 K512[80] = {
+       0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
+       0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+       0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+       0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+       0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
+       0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+       0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
+       0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+       0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+       0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+       0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
+       0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+       0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
+       0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+       0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+       0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+       0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
+       0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+       0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
+       0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+       0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+       0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+       0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
+       0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+       0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
+       0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+       0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+       0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+       0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
+       0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+       0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
+       0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+       0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+       0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+       0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
+       0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+       0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
+       0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+       0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+       0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+/* initial hash value H for SHA-512 */
+static const sha2_word64 sha512_initial_hash_value[8] = {
+       0x6a09e667f3bcc908ULL,
+       0xbb67ae8584caa73bULL,
+       0x3c6ef372fe94f82bULL,
+       0xa54ff53a5f1d36f1ULL,
+       0x510e527fade682d1ULL,
+       0x9b05688c2b3e6c1fULL,
+       0x1f83d9abfb41bd6bULL,
+       0x5be0cd19137e2179ULL
+};
+
+typedef union _ldns_sha2_buffer_union {
+        uint8_t*  theChars;
+        uint64_t* theLongs;
+} ldns_sha2_buffer_union;
+
+/*** SHA-512: *********************************************************/
+void SHA512_Init(SHA512_CTX* context) {
+       if (context == (SHA512_CTX*)0) {
+               return;
+       }
+       MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH);
+       MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH);
+       context->bitcount[0] = context->bitcount[1] =  0;
+}
+
+static void SHA512_Transform(SHA512_CTX* context,
+                                  const sha2_word64* data) {
+       sha2_word64     a, b, c, d, e, f, g, h, s0, s1;
+       sha2_word64     T1, T2, *W512 = (sha2_word64*)context->buffer;
+       int             j;
+
+       /* initialize registers with the prev. intermediate value */
+       a = context->state[0];
+       b = context->state[1];
+       c = context->state[2];
+       d = context->state[3];
+       e = context->state[4];
+       f = context->state[5];
+       g = context->state[6];
+       h = context->state[7];
+
+       j = 0;
+       do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+               /* Convert TO host byte order */
+               REVERSE64(*data++, W512[j]);
+               /* Apply the SHA-512 compression function to update a..h */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+               /* Apply the SHA-512 compression function to update a..h with copy */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+               T2 = Sigma0_512(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 16);
+
+       do {
+               /* Part of the message block expansion: */
+               s0 = W512[(j+1)&0x0f];
+               s0 = sigma0_512(s0);
+               s1 = W512[(j+14)&0x0f];
+               s1 =  sigma1_512(s1);
+
+               /* Apply the SHA-512 compression function to update a..h */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
+                    (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
+               T2 = Sigma0_512(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 80);
+
+       /* Compute the current intermediate hash value */
+       context->state[0] += a;
+       context->state[1] += b;
+       context->state[2] += c;
+       context->state[3] += d;
+       context->state[4] += e;
+       context->state[5] += f;
+       context->state[6] += g;
+       context->state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+void SHA512_Update(SHA512_CTX* context, void *datain, size_t len) {
+       size_t freespace, usedspace;
+       const sha2_byte* data = (const sha2_byte*)datain;
+
+       if (len == 0) {
+               /* Calling with no data is valid - we do nothing */
+               return;
+       }
+
+       /* Sanity check: */
+       assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0);
+
+       usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+       if (usedspace > 0) {
+               /* Calculate how much free space is available in the buffer */
+               freespace = SHA512_BLOCK_LENGTH - usedspace;
+
+               if (len >= freespace) {
+                       /* Fill the buffer completely and process it */
+                       MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace);
+                       ADDINC128(context->bitcount, freespace << 3);
+                       len -= freespace;
+                       data += freespace;
+                       SHA512_Transform(context, (sha2_word64*)context->buffer);
+               } else {
+                       /* The buffer is not yet full */
+                       MEMCPY_BCOPY(&context->buffer[usedspace], data, len);
+                       ADDINC128(context->bitcount, len << 3);
+                       /* Clean up: */
+                       usedspace = freespace = 0;
+                       return;
+               }
+       }
+       while (len >= SHA512_BLOCK_LENGTH) {
+               /* Process as many complete blocks as we can */
+               SHA512_Transform(context, (sha2_word64*)data);
+               ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
+               len -= SHA512_BLOCK_LENGTH;
+               data += SHA512_BLOCK_LENGTH;
+       }
+       if (len > 0) {
+               /* There's left-overs, so save 'em */
+               MEMCPY_BCOPY(context->buffer, data, len);
+               ADDINC128(context->bitcount, len << 3);
+       }
+       /* Clean up: */
+       usedspace = freespace = 0;
+}
+
+static void SHA512_Last(SHA512_CTX* context) {
+       size_t usedspace;
+       ldns_sha2_buffer_union cast_var;
+
+       usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+#if BYTE_ORDER == LITTLE_ENDIAN
+       /* Convert FROM host byte order */
+       REVERSE64(context->bitcount[0],context->bitcount[0]);
+       REVERSE64(context->bitcount[1],context->bitcount[1]);
+#endif
+       if (usedspace > 0) {
+               /* Begin padding with a 1 bit: */
+               context->buffer[usedspace++] = 0x80;
+
+               if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) {
+                       /* Set-up for the last transform: */
+                       MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace);
+               } else {
+                       if (usedspace < SHA512_BLOCK_LENGTH) {
+                               MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace);
+                       }
+                       /* Do second-to-last transform: */
+                       SHA512_Transform(context, (sha2_word64*)context->buffer);
+
+                       /* And set-up for the last transform: */
+                       MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2);
+               }
+       } else {
+               /* Prepare for final transform: */
+               MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH);
+
+               /* Begin padding with a 1 bit: */
+               *context->buffer = 0x80;
+       }
+       /* Store the length of input data (in bits): */
+       cast_var.theChars = context->buffer;
+       cast_var.theLongs[SHA512_SHORT_BLOCK_LENGTH / 8] = context->bitcount[1];
+       cast_var.theLongs[SHA512_SHORT_BLOCK_LENGTH / 8 + 1] = context->bitcount[0];
+
+       /* final transform: */
+       SHA512_Transform(context, (sha2_word64*)context->buffer);
+}
+
+void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {
+       sha2_word64     *d = (sha2_word64*)digest;
+
+       /* Sanity check: */
+       assert(context != (SHA512_CTX*)0);
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != (sha2_byte*)0) {
+               SHA512_Last(context);
+
+               /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+               {
+                       /* Convert TO host byte order */
+                       int     j;
+                       for (j = 0; j < 8; j++) {
+                               REVERSE64(context->state[j],context->state[j]);
+                               *d++ = context->state[j];
+                       }
+               }
+#else
+               MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH);
+#endif
+       }
+
+       /* Zero out state data */
+       MEMSET_BZERO(context, sizeof(SHA512_CTX));
+}
+
+unsigned char *
+SHA512(void *data, unsigned int data_len, unsigned char *digest)
+{
+    SHA512_CTX ctx;
+    SHA512_Init(&ctx);
+    SHA512_Update(&ctx, data, data_len);
+    SHA512_Final(digest, &ctx);
+    return digest;
+}
index 1f5c50c0d1529d50b94dc3533ca72a47f0fa5849..b79252d6b1034cbcce18ed21d4ed21a405f987e9 100755 (executable)
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2014 Free Software Foundation, Inc.
+#   Copyright 1992-2013 Free Software Foundation, Inc.
 
-timestamp='2014-03-23'
+timestamp='2013-06-10'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -50,7 +50,7 @@ version="\
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2014 Free Software Foundation, Inc.
+Copyright 1992-2013 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -149,7 +149,7 @@ Linux|GNU|GNU/*)
        LIBC=gnu
        #endif
        EOF
-       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
        ;;
 esac
 
@@ -826,7 +826,7 @@ EOF
     *:MINGW*:*)
        echo ${UNAME_MACHINE}-pc-mingw32
        exit ;;
-    *:MSYS*:*)
+    i*:MSYS*:*)
        echo ${UNAME_MACHINE}-pc-msys
        exit ;;
     i*:windows32*:*)
@@ -969,10 +969,10 @@ EOF
        eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
        test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
        ;;
-    openrisc*:Linux:*:*)
-       echo or1k-unknown-linux-${LIBC}
+    or1k:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
        exit ;;
-    or32:Linux:*:* | or1k*:Linux:*:*)
+    or32:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
        exit ;;
     padre:Linux:*:*)
@@ -1260,26 +1260,16 @@ EOF
        if test "$UNAME_PROCESSOR" = unknown ; then
            UNAME_PROCESSOR=powerpc
        fi
-       if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
-           if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
-               if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
-                   (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
-                   grep IS_64BIT_ARCH >/dev/null
-               then
-                   case $UNAME_PROCESSOR in
-                       i386) UNAME_PROCESSOR=x86_64 ;;
-                       powerpc) UNAME_PROCESSOR=powerpc64 ;;
-                   esac
-               fi
+       if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+           if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+               (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+               grep IS_64BIT_ARCH >/dev/null
+           then
+               case $UNAME_PROCESSOR in
+                   i386) UNAME_PROCESSOR=x86_64 ;;
+                   powerpc) UNAME_PROCESSOR=powerpc64 ;;
+               esac
            fi
-       elif test "$UNAME_PROCESSOR" = i386 ; then
-           # Avoid executing cc on OS X 10.9, as it ships with a stub
-           # that puts up a graphical alert prompting to install
-           # developer tools.  Any system running Mac OS X 10.7 or
-           # later (Darwin 11 and later) is required to have a 64-bit
-           # processor. This is not true of the ARM version of Darwin
-           # that Apple uses in portable devices.
-           UNAME_PROCESSOR=x86_64
        fi
        echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
        exit ;;
@@ -1371,6 +1361,154 @@ EOF
        exit ;;
 esac
 
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+       "4"
+#else
+       ""
+#endif
+       ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+       { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit ;;
+    c34*)
+       echo c34-convex-bsd
+       exit ;;
+    c38*)
+       echo c38-convex-bsd
+       exit ;;
+    c4*)
+       echo c4-convex-bsd
+       exit ;;
+    esac
+fi
+
 cat >&2 <<EOF
 $0: unable to guess system type
 
index bba4efb80574987fcf6d85c71e68e55bfeb48ba2..d2a9613033047de71a1092ed6ccc6b59306533b2 100755 (executable)
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2014 Free Software Foundation, Inc.
+#   Copyright 1992-2013 Free Software Foundation, Inc.
 
-timestamp='2014-09-11'
+timestamp='2013-08-10'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -68,7 +68,7 @@ Report bugs and patches to <config-patches@gnu.org>."
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2014 Free Software Foundation, Inc.
+Copyright 1992-2013 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -265,7 +265,6 @@ case $basic_machine in
        | hexagon \
        | i370 | i860 | i960 | ia64 \
        | ip2k | iq2000 \
-       | k1om \
        | le32 | le64 \
        | lm32 \
        | m32c | m32r | m32rle | m68000 | m68k | m88k \
@@ -283,10 +282,8 @@ case $basic_machine in
        | mips64vr5900 | mips64vr5900el \
        | mipsisa32 | mipsisa32el \
        | mipsisa32r2 | mipsisa32r2el \
-       | mipsisa32r6 | mipsisa32r6el \
        | mipsisa64 | mipsisa64el \
        | mipsisa64r2 | mipsisa64r2el \
-       | mipsisa64r6 | mipsisa64r6el \
        | mipsisa64sb1 | mipsisa64sb1el \
        | mipsisa64sr71k | mipsisa64sr71kel \
        | mipsr5900 | mipsr5900el \
@@ -298,11 +295,11 @@ case $basic_machine in
        | nds32 | nds32le | nds32be \
        | nios | nios2 | nios2eb | nios2el \
        | ns16k | ns32k \
-       | open8 | or1k | or1knd | or32 \
+       | open8 \
+       | or1k | or32 \
        | pdp10 | pdp11 | pj | pjl \
        | powerpc | powerpc64 | powerpc64le | powerpcle \
        | pyramid \
-       | riscv32 | riscv64 \
        | rl78 | rx \
        | score \
        | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
@@ -327,7 +324,7 @@ case $basic_machine in
        c6x)
                basic_machine=tic6x-unknown
                ;;
-       m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+       m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
                basic_machine=$basic_machine-unknown
                os=-none
                ;;
@@ -384,7 +381,6 @@ case $basic_machine in
        | hexagon-* \
        | i*86-* | i860-* | i960-* | ia64-* \
        | ip2k-* | iq2000-* \
-       | k1om-* \
        | le32-* | le64-* \
        | lm32-* \
        | m32c-* | m32r-* | m32rle-* \
@@ -404,10 +400,8 @@ case $basic_machine in
        | mips64vr5900-* | mips64vr5900el-* \
        | mipsisa32-* | mipsisa32el-* \
        | mipsisa32r2-* | mipsisa32r2el-* \
-       | mipsisa32r6-* | mipsisa32r6el-* \
        | mipsisa64-* | mipsisa64el-* \
        | mipsisa64r2-* | mipsisa64r2el-* \
-       | mipsisa64r6-* | mipsisa64r6el-* \
        | mipsisa64sb1-* | mipsisa64sb1el-* \
        | mipsisa64sr71k-* | mipsisa64sr71kel-* \
        | mipsr5900-* | mipsr5900el-* \
@@ -419,7 +413,6 @@ case $basic_machine in
        | nios-* | nios2-* | nios2eb-* | nios2el-* \
        | none-* | np1-* | ns16k-* | ns32k-* \
        | open8-* \
-       | or1k*-* \
        | orion-* \
        | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
        | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
@@ -829,10 +822,6 @@ case $basic_machine in
                basic_machine=powerpc-unknown
                os=-morphos
                ;;
-       moxiebox)
-               basic_machine=moxie-unknown
-               os=-moxiebox
-               ;;
        msdos)
                basic_machine=i386-pc
                os=-msdos
@@ -1017,7 +1006,7 @@ case $basic_machine in
                ;;
        ppc64)  basic_machine=powerpc64-unknown
                ;;
-       ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+       ppc64-* | ppc64p7-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
                ;;
        ppc64le | powerpc64little | ppc64-le | powerpc64-little)
                basic_machine=powerpc64le-unknown
@@ -1378,14 +1367,14 @@ case $os in
              | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
              | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
              | -linux-newlib* | -linux-musl* | -linux-uclibc* \
-             | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+             | -uxpv* | -beos* | -mpeix* | -udk* \
              | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
              | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
              | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
              | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
              | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
              | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
-             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
        # Remember, each alternative MUST END IN *, to match a version number.
                ;;
        -qnx*)
@@ -1603,6 +1592,9 @@ case $basic_machine in
        mips*-*)
                os=-elf
                ;;
+       or1k-*)
+               os=-elf
+               ;;
        or32-*)
                os=-coff
                ;;
diff --git a/contrib/aaaa-filter-iterator.patch b/contrib/aaaa-filter-iterator.patch
new file mode 100644 (file)
index 0000000..8e03d7c
--- /dev/null
@@ -0,0 +1,394 @@
+--- unbound-1.4.17.orig/doc/unbound.conf.5.in
++++ unbound-1.4.17/doc/unbound.conf.5.in
+@@ -519,6 +519,13 @@ authority servers and checks if the repl
+ Disabled by default. 
+ This feature is an experimental implementation of draft dns\-0x20.
+ .TP
++.B aaaa\-filter: \fI<yes or no>
++Activate behavior similar to BIND's AAAA-filter.
++This forces the dropping of all AAAA records, unless in the case of
++explicit AAAA queries, when no A records have been confirmed.
++This also causes an additional A query to be sent for each AAAA query.
++This breaks DNSSEC!
++.TP
+ .B private\-address: \fI<IP address or subnet>
+ Give IPv4 of IPv6 addresses or classless subnets. These are addresses
+ on your private network, and are not allowed to be returned for public
+--- unbound-1.4.17.orig/util/config_file.c
++++ unbound-1.4.17/util/config_file.c
+@@ -160,6 +160,7 @@ config_create(void)
+       cfg->harden_below_nxdomain = 0;
+       cfg->harden_referral_path = 0;
+       cfg->use_caps_bits_for_id = 0;
++      cfg->aaaa_filter = 0; /* ASN: default is disabled */
+       cfg->private_address = NULL;
+       cfg->private_domain = NULL;
+       cfg->unwanted_threshold = 0;
+--- unbound-1.4.17.orig/iterator/iter_scrub.c
++++ unbound-1.4.17/iterator/iter_scrub.c
+@@ -580,6 +580,32 @@ static int sanitize_nsec_is_overreach(st
+ }
+ /**
++ * ASN: Lookup A records from rrset cache.
++ * @param qinfo: the question originally asked.
++ * @param env: module environment with config and cache.
++ * @param ie: iterator environment with private address data.
++ * @return 0 if no A record found, 1 if A record found.
++ */
++static int
++asn_lookup_a_record_from_cache(struct query_info* qinfo,
++      struct module_env* env, struct iter_env* ie)
++{
++      struct ub_packed_rrset_key* akey;
++
++      /* get cached A records for queried name */
++      akey = rrset_cache_lookup(env->rrset_cache, qinfo->qname,
++              qinfo->qname_len, LDNS_RR_TYPE_A, qinfo->qclass,
++              0, *env->now, 0);
++      if(akey) { /* we had some. */
++              log_rrset_key(VERB_ALGO, "ASN-AAAA-filter: found A record",
++                            akey);
++              lock_rw_unlock(&akey->entry.lock);
++              return 1;
++      }
++      return 0;
++}
++
++/**
+  * Given a response event, remove suspect RRsets from the response.
+  * "Suspect" rrsets are potentially poison. Note that this routine expects
+  * the response to be in a "normalized" state -- that is, all "irrelevant"
+@@ -598,6 +625,7 @@ scrub_sanitize(ldns_buffer* pkt, struct
+       struct query_info* qinfo, uint8_t* zonename, struct module_env* env,
+       struct iter_env* ie)
+ {
++      int found_a_record = 0; /* ASN: do we have a A record? */
+       int del_addi = 0; /* if additional-holding rrsets are deleted, we
+               do not trust the normalized additional-A-AAAA any more */
+       struct rrset_parse* rrset, *prev;
+@@ -633,6 +661,13 @@ scrub_sanitize(ldns_buffer* pkt, struct
+               rrset = rrset->rrset_all_next;
+       }
++      /* ASN: Locate any A record we can find */
++      if((ie->aaaa_filter) && (qinfo->qtype == LDNS_RR_TYPE_AAAA)) {
++              found_a_record = asn_lookup_a_record_from_cache(qinfo,
++                      env, ie);
++      }
++      /* ASN: End of added code */
++
+       /* At this point, we brutally remove ALL rrsets that aren't 
+        * children of the originating zone. The idea here is that, 
+        * as far as we know, the server that we contacted is ONLY 
+@@ -644,6 +679,24 @@ scrub_sanitize(ldns_buffer* pkt, struct
+       rrset = msg->rrset_first;
+       while(rrset) {
++              /* ASN: For AAAA records only... */
++              if((ie->aaaa_filter) && (rrset->type == LDNS_RR_TYPE_AAAA)) {
++                      /* ASN: If this is not a AAAA query, then remove AAAA
++                       * records, no questions asked. If this IS a AAAA query
++                       * then remove AAAA records if we have an A record.
++                       * Otherwise, leave things be. */
++                      if((qinfo->qtype != LDNS_RR_TYPE_AAAA) ||
++                              (found_a_record)) {
++                              remove_rrset("ASN-AAAA-filter: removing AAAA "
++                                      "for record", pkt, msg, prev, &rrset);
++                              continue;
++                      }
++                      log_nametypeclass(VERB_ALGO, "ASN-AAAA-filter: "
++                              "keep AAAA for", zonename,
++                              LDNS_RR_TYPE_AAAA, qinfo->qclass);
++              }
++              /* ASN: End of added code */
++
+               /* remove private addresses */
+               if( (rrset->type == LDNS_RR_TYPE_A || 
+                       rrset->type == LDNS_RR_TYPE_AAAA) &&
+--- unbound-1.4.17.orig/iterator/iterator.c
++++ unbound-1.4.17/iterator/iterator.c
+@@ -1579,6 +1579,53 @@ processDSNSFind(struct module_qstate* qs
+       return 0;
+ }
++
++/**
++ * ASN: This event state was added as an intermediary step between
++ * QUERYTARGETS_STATE and the next step, in order to cast a subquery for the
++ * purpose of caching A records for the queried name.
++ * 
++ * @param qstate: query state.
++ * @param iq: iterator query state.
++ * @param ie: iterator shared global environment.
++ * @param id: module id.
++ * @return true if the event requires more request processing immediately,
++ *         false if not. This state only returns true when it is generating
++ *         a SERVFAIL response because the query has hit a dead end.
++ */
++static int
++asn_processQueryAAAA(struct module_qstate* qstate, struct iter_qstate* iq,
++      struct iter_env* ie, int id)
++{
++      struct module_qstate* subq = NULL;
++
++      log_assert(iq->fetch_a_for_aaaa == 0);
++
++      /* flag the query properly in order to not loop */
++      iq->fetch_a_for_aaaa = 1;
++
++      /* re-throw same query, but with a different type */
++      if(!generate_sub_request(iq->qchase.qname,
++              iq->qchase.qname_len, LDNS_RR_TYPE_A,
++              iq->qchase.qclass, qstate, id, iq,
++              INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1)) {
++              log_nametypeclass(VERB_ALGO, "ASN-AAAA-filter: failed "
++                      "preloading of A record for",
++                      iq->qchase.qname, LDNS_RR_TYPE_A,
++                      iq->qchase.qclass);
++              return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
++      }
++      log_nametypeclass(VERB_ALGO, "ASN-AAAA-filter: "
++              "preloading records in cache for",
++              iq->qchase.qname, LDNS_RR_TYPE_A,
++              iq->qchase.qclass);
++
++      /* set this query as waiting */
++      qstate->ext_state[id] = module_wait_subquery;
++      /* at this point break loop */
++      return 0;
++}
++/* ASN: End of added code */
+       
+ /** 
+  * This is the request event state where the request will be sent to one of
+@@ -1626,6 +1673,13 @@ processQueryTargets(struct module_qstate
+               return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+       }
+       
++      /* ASN: If we have a AAAA query, then also query for A records */
++      if((ie->aaaa_filter) && (iq->qchase.qtype == LDNS_RR_TYPE_AAAA) &&
++              (iq->fetch_a_for_aaaa == 0)) {
++              return next_state(iq, ASN_FETCH_A_FOR_AAAA_STATE);
++      }
++      /* ASN: End of added code */
++
+       /* Make sure we have a delegation point, otherwise priming failed
+        * or another failure occurred */
+       if(!iq->dp) {
+@@ -2568,6 +2622,62 @@ processFinished(struct module_qstate* qs
+       return 0;
+ }
++/** 
++ * ASN: Do final processing on responses to A queries originated from AAAA
++ * queries. Events reach this state after the iterative resolution algorithm
++ * terminates.
++ * This is required down the road to decide whether to scrub AAAA records
++ * from the results or not.
++ *
++ * @param qstate: query state.
++ * @param id: module id.
++ * @param forq: super query state.
++ */
++static void
++asn_processAAAAResponse(struct module_qstate* qstate, int id,
++      struct module_qstate* super)
++{
++      struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id];
++      struct iter_qstate* super_iq = (struct iter_qstate*)super->minfo[id];
++      struct ub_packed_rrset_key* rrset;
++      struct delegpt_ns* dpns = NULL;
++      int error = (qstate->return_rcode != LDNS_RCODE_NOERROR);
++
++      log_assert(super_iq->fetch_a_for_aaaa > 0);
++
++      /* let super go to evaluation of targets after this */
++      super_iq->state = QUERYTARGETS_STATE;
++
++      log_query_info(VERB_ALGO, "ASN-AAAA-filter: processAAAAResponse",
++              &qstate->qinfo);
++      log_query_info(VERB_ALGO, "ASN-AAAA-filter: processAAAAResponse super",
++              &super->qinfo);
++
++      if(super_iq->dp)
++              dpns = delegpt_find_ns(super_iq->dp,
++                      qstate->qinfo.qname, qstate->qinfo.qname_len);
++      if (!dpns) {
++              /* not interested */
++              verbose(VERB_ALGO, "ASN-AAAA-filter: subq: %s, but parent not "
++                      "interested%s", (error ? "error, but" : "success"),
++                      (super_iq->dp ? "anymore" : " (was reset)"));
++              log_query_info(VERB_ALGO, "ASN-AAAA-filter: superq", &super->qinfo);
++              if(super_iq->dp && error)
++                      delegpt_log(VERB_ALGO, super_iq->dp);
++              return;
++      } else if (error) {
++              verbose(VERB_ALGO, "ASN-AAAA-filter: mark as failed, "
++                      "and go to target query.");
++              /* see if the failure did get (parent-lame) info */
++              if(!cache_fill_missing(super->env,
++                      super_iq->qchase.qclass, super->region,
++                      super_iq->dp))
++              log_err("ASN-AAAA-filter: out of memory adding missing");
++              dpns->resolved = 1; /* mark as failed */
++      }
++}
++/* ASN: End of added code */
++
+ /*
+  * Return priming query results to interestes super querystates.
+  * 
+@@ -2587,6 +2697,9 @@ iter_inform_super(struct module_qstate*
+       else if(super->qinfo.qtype == LDNS_RR_TYPE_DS && ((struct iter_qstate*)
+               super->minfo[id])->state == DSNS_FIND_STATE)
+               processDSNSResponse(qstate, id, super);
++      else if (super->qinfo.qtype == LDNS_RR_TYPE_AAAA && ((struct iter_qstate*)
++              super->minfo[id])->state == ASN_FETCH_A_FOR_AAAA_STATE)
++              asn_processAAAAResponse(qstate, id, super);
+       else if(qstate->return_rcode != LDNS_RCODE_NOERROR)
+               error_supers(qstate, id, super);
+       else if(qstate->is_priming)
+@@ -2624,6 +2737,9 @@ iter_handle(struct module_qstate* qstate
+                       case INIT_REQUEST_3_STATE:
+                               cont = processInitRequest3(qstate, iq, id);
+                               break;
++                      case ASN_FETCH_A_FOR_AAAA_STATE:
++                              cont = asn_processQueryAAAA(qstate, iq, ie, id);
++                              break;
+                       case QUERYTARGETS_STATE:
+                               cont = processQueryTargets(qstate, iq, ie, id);
+                               break;
+@@ -2863,6 +2979,8 @@ iter_state_to_string(enum iter_state sta
+               return "INIT REQUEST STATE (stage 2)";
+       case INIT_REQUEST_3_STATE:
+               return "INIT REQUEST STATE (stage 3)";
++      case ASN_FETCH_A_FOR_AAAA_STATE:
++              return "ASN_FETCH_A_FOR_AAAA_STATE";
+       case QUERYTARGETS_STATE :
+               return "QUERY TARGETS STATE";
+       case PRIME_RESP_STATE :
+@@ -2887,6 +3005,7 @@ iter_state_is_responsestate(enum iter_st
+               case INIT_REQUEST_STATE :
+               case INIT_REQUEST_2_STATE :
+               case INIT_REQUEST_3_STATE :
++              case ASN_FETCH_A_FOR_AAAA_STATE :
+               case QUERYTARGETS_STATE :
+               case COLLECT_CLASS_STATE :
+                       return 0;
+--- unbound-1.4.17.orig/iterator/iter_utils.c
++++ unbound-1.4.17/iterator/iter_utils.c
+@@ -128,6 +128,7 @@ iter_apply_cfg(struct iter_env* iter_env
+       }
+       iter_env->supports_ipv6 = cfg->do_ip6;
+       iter_env->supports_ipv4 = cfg->do_ip4;
++      iter_env->aaaa_filter = cfg->aaaa_filter;
+       return 1;
+ }
+--- unbound-1.4.17.orig/iterator/iterator.h
++++ unbound-1.4.17/iterator/iterator.h
+@@ -110,6 +110,9 @@ struct iter_env {
+        * array of max_dependency_depth+1 size.
+        */
+       int* target_fetch_policy;
++
++      /** ASN: AAAA-filter flag */
++      int aaaa_filter;
+ };
+ /**
+@@ -135,6 +138,14 @@ enum iter_state {
+       INIT_REQUEST_3_STATE,
+       /**
++       * This state is responsible for intercepting AAAA queries,
++       * and launch a A subquery on the same target, to populate the
++       * cache with A records, so the AAAA filter scrubbing logic can
++       * work.
++       */
++      ASN_FETCH_A_FOR_AAAA_STATE,
++
++      /**
+        * Each time a delegation point changes for a given query or a 
+        * query times out and/or wakes up, this state is (re)visited. 
+        * This state is reponsible for iterating through a list of 
+@@ -309,6 +320,13 @@ struct iter_qstate {
+        */
+       int refetch_glue;
++      /**
++       * ASN: This is a flag that, if true, means that this query is
++       * for fetching A records to populate cache and determine if we must
++       * return AAAA records or not.
++       */
++      int fetch_a_for_aaaa;
++
+       /** list of pending queries to authoritative servers. */
+       struct outbound_list outlist;
+ };
+--- unbound-1.4.17.orig/util/config_file.h
++++ unbound-1.4.17/util/config_file.h
+@@ -169,6 +169,8 @@ struct config_file {
+       int harden_referral_path;
+       /** use 0x20 bits in query as random ID bits */
+       int use_caps_bits_for_id;
++      /** ASN: enable AAAA filter? */
++      int aaaa_filter;
+       /** strip away these private addrs from answers, no DNS Rebinding */
+       struct config_strlist* private_address;
+       /** allow domain (and subdomains) to use private address space */
+--- unbound-1.4.17.orig/util/configlexer.lex
++++ unbound-1.4.17/util/configlexer.lex
+@@ -177,6 +177,7 @@ harden-below-nxdomain{COLON}       { YDVAR(1,
+ harden-referral-path{COLON}   { YDVAR(1, VAR_HARDEN_REFERRAL_PATH) }
+ use-caps-for-id{COLON}                { YDVAR(1, VAR_USE_CAPS_FOR_ID) }
+ unwanted-reply-threshold{COLON}       { YDVAR(1, VAR_UNWANTED_REPLY_THRESHOLD) }
++aaaa-filter{COLON}            { YDVAR(1, VAR_AAAA_FILTER) }
+ private-address{COLON}                { YDVAR(1, VAR_PRIVATE_ADDRESS) }
+ private-domain{COLON}         { YDVAR(1, VAR_PRIVATE_DOMAIN) }
+ prefetch-key{COLON}           { YDVAR(1, VAR_PREFETCH_KEY) }
+--- unbound-1.4.17.orig/util/configparser.y
++++ unbound-1.4.17/util/configparser.y
+@@ -92,6 +92,7 @@ extern struct config_parser_state* cfg_p
+ %token VAR_STATISTICS_CUMULATIVE VAR_OUTGOING_PORT_PERMIT 
+ %token VAR_OUTGOING_PORT_AVOID VAR_DLV_ANCHOR_FILE VAR_DLV_ANCHOR
+ %token VAR_NEG_CACHE_SIZE VAR_HARDEN_REFERRAL_PATH VAR_PRIVATE_ADDRESS
++%token VAR_AAAA_FILTER
+ %token VAR_PRIVATE_DOMAIN VAR_REMOTE_CONTROL VAR_CONTROL_ENABLE
+ %token VAR_CONTROL_INTERFACE VAR_CONTROL_PORT VAR_SERVER_KEY_FILE
+ %token VAR_SERVER_CERT_FILE VAR_CONTROL_KEY_FILE VAR_CONTROL_CERT_FILE
+@@ -151,6 +152,7 @@ content_server: server_num_threads | ser
+       server_dlv_anchor_file | server_dlv_anchor | server_neg_cache_size |
+       server_harden_referral_path | server_private_address |
+       server_private_domain | server_extended_statistics | 
++      server_aaaa_filter |
+       server_local_data_ptr | server_jostle_timeout | 
+       server_unwanted_reply_threshold | server_log_time_ascii | 
+       server_domain_insecure | server_val_sig_skew_min | 
+@@ -802,6 +803,15 @@ server_use_caps_for_id: VAR_USE_CAPS_FOR
+               free($2);
+       }
+       ;
++server_aaaa_filter: VAR_AAAA_FILTER STRING_ARG
++      {
++              OUTYY(("P(server_aaaa_filter:%s)\n", $2));
++              if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
++                      yyerror("expected yes or no.");
++              else cfg_parser->cfg->aaaa_filter = (strcmp($2, "yes")==0);
++              free($2);
++      }
++      ;
+ server_private_address: VAR_PRIVATE_ADDRESS STRING_ARG
+       {
+               OUTYY(("P(server_private_address:%s)\n", $2));
+--- unbound-1.4.17.orig/pythonmod/interface.i
++++ unbound-1.4.17/pythonmod/interface.i
+@@ -626,6 +626,7 @@ struct config_file {
+    int harden_dnssec_stripped;
+    int harden_referral_path;
+    int use_caps_bits_for_id;
++   int aaaa_filter; /* ASN */
+    struct config_strlist* private_address;
+    struct config_strlist* private_domain;
+    size_t unwanted_threshold;
diff --git a/contrib/unbound_smf22.tar.gz b/contrib/unbound_smf22.tar.gz
new file mode 100644 (file)
index 0000000..e4c51c3
Binary files /dev/null and b/contrib/unbound_smf22.tar.gz differ
diff --git a/dns64/dns64.c b/dns64/dns64.c
new file mode 100644 (file)
index 0000000..63cc808
--- /dev/null
@@ -0,0 +1,873 @@
+/*
+ * dns64/dns64.c - DNS64 module
+ *
+ * Copyright (c) 2009, Viagénie. All rights reserved.
+ *
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of Viagénie nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file contains a module that performs DNS64 query processing.
+ */
+
+#include "config.h"
+#include "dns64/dns64.h"
+#include "services/cache/dns.h"
+#include "services/cache/rrset.h"
+#include "util/config_file.h"
+#include "util/data/msgreply.h"
+#include "util/fptr_wlist.h"
+#include "util/net_help.h"
+#include "util/regional.h"
+
+/******************************************************************************
+ *                                                                            *
+ *                             STATIC CONSTANTS                               *
+ *                                                                            *
+ ******************************************************************************/
+
+/**
+ * This is the default DNS64 prefix that is used whent he dns64 module is listed
+ * in module-config but when the dns64-prefix variable is not present.
+ */
+static const char DEFAULT_DNS64_PREFIX[] = "64:ff9b::/96";
+
+/**
+ * Maximum length of a domain name in a PTR query in the .in-addr.arpa tree.
+ */
+#define MAX_PTR_QNAME_IPV4 30
+
+/**
+ * Per-query module-specific state. This is usually a dynamically-allocated
+ * structure, but in our case we only need to store one variable describing the
+ * state the query is in. So we repurpose the minfo pointer by storing an
+ * integer in there.
+ */
+enum dns64_qstate {
+    DNS64_INTERNAL_QUERY,    /**< Internally-generated query, no DNS64
+                                  processing. */
+    DNS64_NEW_QUERY,         /**< Query for which we're the first module in
+                                  line. */
+    DNS64_SUBQUERY_FINISHED  /**< Query for which we generated a sub-query, and
+                                  for which this sub-query is finished. */
+};
+
+
+/******************************************************************************
+ *                                                                            *
+ *                                 STRUCTURES                                 *
+ *                                                                            *
+ ******************************************************************************/
+
+/**
+ * This structure contains module configuration information. One instance of
+ * this structure exists per instance of the module. Normally there is only one
+ * instance of the module.
+ */
+struct dns64_env {
+    /**
+     * DNS64 prefix address. We're using a full sockaddr instead of just an
+     * in6_addr because we can reuse Unbound's generic string parsing functions.
+     * It will always contain a sockaddr_in6, and only the sin6_addr member will
+     * ever be used.
+     */
+    struct sockaddr_storage prefix_addr;
+
+    /**
+     * This is always sizeof(sockaddr_in6).
+     */
+    socklen_t prefix_addrlen;
+
+    /**
+     * This is the CIDR length of the prefix. It needs to be between 0 and 96.
+     */
+    int prefix_net;
+};
+
+
+/******************************************************************************
+ *                                                                            *
+ *                             UTILITY FUNCTIONS                              *
+ *                                                                            *
+ ******************************************************************************/
+
+/**
+ * Generic macro for swapping two variables.
+ *
+ * \param t Type of the variables. (e.g. int)
+ * \param a First variable.
+ * \param b Second variable.
+ *
+ * \warning Do not attempt something foolish such as swap(int,a++,b++)!
+ */
+#define swap(t,a,b) do {t x = a; a = b; b = x;} while(0)
+
+/**
+ * Reverses a string.
+ *
+ * \param begin Points to the first character of the string.
+ * \param end   Points one past the last character of the string.
+ */
+static void
+reverse(char* begin, char* end)
+{
+    while ( begin < --end ) {
+        swap(char, *begin, *end);
+        ++begin;
+    }
+}
+
+/**
+ * Convert an unsigned integer to a string. The point of this function is that
+ * of being faster than sprintf().
+ *
+ * \param n The number to be converted.
+ * \param s The result will be written here. Must be large enough, be careful!
+ *
+ * \return The number of characters written.
+ */
+static int
+uitoa(unsigned n, char* s)
+{
+    char* ss = s;
+    do {
+        *ss++ = '0' + n % 10;
+    } while (n /= 10);
+    reverse(s, ss);
+    return ss - s;
+}
+
+/**
+ * Extract an IPv4 address embedded in the IPv6 address \a ipv6 at offset \a
+ * offset (in bits). Note that bits are not necessarily aligned on bytes so we
+ * need to be careful.
+ *
+ * \param ipv6   IPv6 address represented as a 128-bit array in big-endian
+ *               order.
+ * \param offset Index of the MSB of the IPv4 address embedded in the IPv6
+ *               address.
+ */
+static uint32_t
+extract_ipv4(const uint8_t ipv6[16], const int offset)
+{
+    uint32_t ipv4 = (uint32_t)ipv6[offset/8+0] << (24 + (offset%8))
+                  | (uint32_t)ipv6[offset/8+1] << (16 + (offset%8))
+                  | (uint32_t)ipv6[offset/8+2] << ( 8 + (offset%8))
+                  | (uint32_t)ipv6[offset/8+3] << ( 0 + (offset%8));
+    if (offset/8+4 < 16)
+        ipv4 |= (uint32_t)ipv6[offset/8+4] >> (8 - offset%8);
+    return ipv4;
+}
+
+/**
+ * Builds the PTR query name corresponding to an IPv4 address. For example,
+ * given the number 3,464,175,361, this will build the string
+ * "\03206\03123\0231\011\07in-addr\04arpa".
+ *
+ * \param ipv4 IPv4 address represented as an unsigned 32-bit number.
+ * \param ptr  The result will be written here. Must be large enough, be
+ *             careful!
+ *
+ * \return The number of characters written.
+ */
+static size_t
+ipv4_to_ptr(uint32_t ipv4, char ptr[MAX_PTR_QNAME_IPV4])
+{
+    static const char IPV4_PTR_SUFFIX[] = "\07in-addr\04arpa";
+    int i;
+    char* c = ptr;
+
+    for (i = 0; i < 4; ++i) {
+        *c = uitoa((unsigned int)(ipv4 % 256), c + 1);
+        c += *c + 1;
+        ipv4 /= 256;
+    }
+
+    memmove(c, IPV4_PTR_SUFFIX, sizeof(IPV4_PTR_SUFFIX));
+
+    return c + sizeof(IPV4_PTR_SUFFIX) - ptr;
+}
+
+/**
+ * Converts an IPv6-related domain name string from a PTR query into an IPv6
+ * address represented as a 128-bit array.
+ *
+ * \param ptr  The domain name. (e.g. "\011[...]\010\012\016\012\03ip6\04arpa")
+ * \param ipv6 The result will be written here, in network byte order.
+ *
+ * \return 1 on success, 0 on failure.
+ */
+static int
+ptr_to_ipv6(const char* ptr, uint8_t ipv6[16])
+{
+    int i;
+
+    for (i = 0; i < 64; i++) {
+        int x;
+
+        if (ptr[i++] != 1)
+            return 0;
+
+        if (ptr[i] >= '0' && ptr[i] <= '9') {
+            x = ptr[i] - '0';
+        } else if (ptr[i] >= 'a' && ptr[i] <= 'f') {
+            x = ptr[i] - 'a' + 10;
+        } else if (ptr[i] >= 'A' && ptr[i] <= 'F') {
+            x = ptr[i] - 'A' + 10;
+        } else {
+            return 0;
+        }
+
+        ipv6[15-i/4] |= x << (2 * ((i-1) % 4));
+    }
+
+    return 1;
+}
+
+/**
+ * Synthesize an IPv6 address based on an IPv4 address and the DNS64 prefix.
+ *
+ * \param prefix_addr DNS64 prefix address.
+ * \param prefix_net  CIDR length of the DNS64 prefix. Must be between 0 and 96.
+ * \param a           IPv4 address.
+ * \param aaaa        IPv6 address. The result will be written here.
+ */
+static void
+synthesize_aaaa(const uint8_t prefix_addr[16], int prefix_net,
+        const uint8_t a[4], uint8_t aaaa[16])
+{
+    memcpy(aaaa, prefix_addr, 16);
+    aaaa[prefix_net/8+0] |= a[0] >> (0+prefix_net%8);
+    aaaa[prefix_net/8+1] |= a[0] << (8-prefix_net%8);
+    aaaa[prefix_net/8+1] |= a[1] >> (0+prefix_net%8);
+    aaaa[prefix_net/8+2] |= a[1] << (8-prefix_net%8);
+    aaaa[prefix_net/8+2] |= a[2] >> (0+prefix_net%8);
+    aaaa[prefix_net/8+3] |= a[2] << (8-prefix_net%8);
+    aaaa[prefix_net/8+3] |= a[3] >> (0+prefix_net%8);
+    if (prefix_net/8+4 < 16)  /* <-- my beautiful symmetry is destroyed! */
+    aaaa[prefix_net/8+4] |= a[3] << (8-prefix_net%8);
+}
+
+
+/******************************************************************************
+ *                                                                            *
+ *                           DNS64 MODULE FUNCTIONS                           *
+ *                                                                            *
+ ******************************************************************************/
+
+/**
+ * This function applies the configuration found in the parsed configuration
+ * file \a cfg to this instance of the dns64 module. Currently only the DNS64
+ * prefix (a.k.a. Pref64) is configurable.
+ *
+ * \param dns64_env Module-specific global parameters.
+ * \param cfg       Parsed configuration file.
+ */
+static int
+dns64_apply_cfg(struct dns64_env* dns64_env, struct config_file* cfg)
+{
+    verbose(VERB_ALGO, "dns64-prefix: %s", cfg->dns64_prefix);
+    if (!netblockstrtoaddr(cfg->dns64_prefix ? cfg->dns64_prefix :
+                DEFAULT_DNS64_PREFIX, 0, &dns64_env->prefix_addr,
+                &dns64_env->prefix_addrlen, &dns64_env->prefix_net)) {
+        log_err("cannot parse dns64-prefix netblock: %s", cfg->dns64_prefix);
+        return 0;
+    }
+    if (!addr_is_ip6(&dns64_env->prefix_addr, dns64_env->prefix_addrlen)) {
+        log_err("dns64_prefix is not IPv6: %s", cfg->dns64_prefix);
+        return 0;
+    }
+    if (dns64_env->prefix_net < 0 || dns64_env->prefix_net > 96) {
+        log_err("dns64-prefix length it not between 0 and 96: %s",
+                cfg->dns64_prefix);
+        return 0;
+    }
+    return 1;
+}
+
+/**
+ * Initializes this instance of the dns64 module.
+ *
+ * \param env Global state of all module instances.
+ * \param id  This instance's ID number.
+ */
+int
+dns64_init(struct module_env* env, int id)
+{
+    struct dns64_env* dns64_env =
+        (struct dns64_env*)calloc(1, sizeof(struct dns64_env));
+    if (!dns64_env) {
+        log_err("malloc failure");
+        return 0;
+    }
+       env->modinfo[id] = (void*)dns64_env;
+    if (!dns64_apply_cfg(dns64_env, env->cfg)) {
+        log_err("dns64: could not apply configuration settings.");
+        return 0;
+    }
+    return 1;
+}
+
+/**
+ * Deinitializes this instance of the dns64 module.
+ *
+ * \param env Global state of all module instances.
+ * \param id  This instance's ID number.
+ */
+void
+dns64_deinit(struct module_env* env, int id)
+{
+    if (!env)
+        return;
+    free(env->modinfo[id]);
+    env->modinfo[id] = NULL;
+}
+
+/**
+ * Handle PTR queries for IPv6 addresses. If the address belongs to the DNS64
+ * prefix, we must do a PTR query for the corresponding IPv4 address instead.
+ *
+ * \param qstate Query state structure.
+ * \param id     This module instance's ID number.
+ *
+ * \return The new state of the query.
+ */
+static enum module_ext_state
+handle_ipv6_ptr(struct module_qstate* qstate, int id)
+{
+    struct dns64_env* dns64_env = (struct dns64_env*)qstate->env->modinfo[id];
+    struct module_qstate* subq = NULL;
+    struct query_info qinfo;
+    struct sockaddr_in6 sin6;
+
+    /* Convert the PTR query string to an IPv6 address. */
+    memset(&sin6, 0, sizeof(sin6));
+    sin6.sin6_family = AF_INET6;
+    if (!ptr_to_ipv6((char*)qstate->qinfo.qname, sin6.sin6_addr.s6_addr))
+        return module_wait_module;  /* Let other module handle this. */
+
+    /*
+     * If this IPv6 address is not part of our DNS64 prefix, then we don't need
+     * to do anything. Let another module handle the query.
+     */
+    if (addr_in_common((struct sockaddr_storage*)&sin6, 128,
+                &dns64_env->prefix_addr, dns64_env->prefix_net,
+                (socklen_t)sizeof(sin6)) != dns64_env->prefix_net)
+        return module_wait_module;
+
+    verbose(VERB_ALGO, "dns64: rewrite PTR record");
+
+    /*
+     * Create a new PTR query info for the domain name corresponding to the IPv4
+     * address corresponding to the IPv6 address corresponding to the original
+     * PTR query domain name.
+     */
+    qinfo = qstate->qinfo;
+    if (!(qinfo.qname = regional_alloc(qstate->region, MAX_PTR_QNAME_IPV4)))
+        return module_error;
+    qinfo.qname_len = ipv4_to_ptr(extract_ipv4(sin6.sin6_addr.s6_addr,
+                dns64_env->prefix_net), (char*)qinfo.qname);
+
+    /* Create the new sub-query. */
+    fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
+    if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0, 0,
+                &subq))
+        return module_error;
+    if (subq) {
+        subq->curmod = id;
+        subq->ext_state[id] = module_state_initial;
+        subq->minfo[id] = NULL;
+    }
+
+    return module_wait_subquery;
+}
+
+/** allocate (special) rrset keys, return 0 on error */
+static int
+repinfo_alloc_rrset_keys(struct reply_info* rep, 
+       struct regional* region)
+{
+       size_t i;
+       for(i=0; i<rep->rrset_count; i++) {
+               if(region) {
+                       rep->rrsets[i] = (struct ub_packed_rrset_key*)
+                               regional_alloc(region, 
+                               sizeof(struct ub_packed_rrset_key));
+                       if(rep->rrsets[i]) {
+                               memset(rep->rrsets[i], 0, 
+                                       sizeof(struct ub_packed_rrset_key));
+                               rep->rrsets[i]->entry.key = rep->rrsets[i];
+                       }
+               }
+               else return 0;/*        rep->rrsets[i] = alloc_special_obtain(alloc);*/
+               if(!rep->rrsets[i])
+                       return 0;
+               rep->rrsets[i]->entry.data = NULL;
+       }
+       return 1;
+}
+
+static enum module_ext_state
+generate_type_A_query(struct module_qstate* qstate, int id)
+{
+       struct module_qstate* subq = NULL;
+       struct query_info qinfo;
+
+       verbose(VERB_ALGO, "dns64: query A record");
+
+       /* Create a new query info. */
+       qinfo = qstate->qinfo;
+       qinfo.qtype = LDNS_RR_TYPE_A;
+
+       /* Start the sub-query. */
+       fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
+       if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0,
+                                      0, &subq))
+       {
+               verbose(VERB_ALGO, "dns64: sub-query creation failed");
+               return module_error;
+       }
+       if (subq) {
+               subq->curmod = id;
+               subq->ext_state[id] = module_state_initial;
+               subq->minfo[id] = NULL;
+       }
+
+       return module_wait_subquery;
+}
+
+/**
+ * Handles the "pass" event for a query. This event is received when a new query
+ * is received by this module. The query may have been generated internally by
+ * another module, in which case we don't want to do any special processing
+ * (this is an interesting discussion topic),  or it may be brand new, e.g.
+ * received over a socket, in which case we do want to apply DNS64 processing.
+ *
+ * \param qstate A structure representing the state of the query that has just
+ *               received the "pass" event.
+ * \param id     This module's instance ID.
+ *
+ * \return The new state of the query.
+ */
+static enum module_ext_state
+handle_event_pass(struct module_qstate* qstate, int id)
+{
+       if ((uintptr_t)qstate->minfo[id] == DNS64_NEW_QUERY
+            && qstate->qinfo.qtype == LDNS_RR_TYPE_PTR
+            && qstate->qinfo.qname_len == 74
+            && !strcmp((char*)&qstate->qinfo.qname[64], "\03ip6\04arpa"))
+        /* Handle PTR queries for IPv6 addresses. */
+        return handle_ipv6_ptr(qstate, id);
+
+       if (qstate->env->cfg->dns64_synthall &&
+           (uintptr_t)qstate->minfo[id] == DNS64_NEW_QUERY
+           && qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA)
+               return generate_type_A_query(qstate, id);
+
+       /* We are finished when our sub-query is finished. */
+       if ((uintptr_t)qstate->minfo[id] == DNS64_SUBQUERY_FINISHED)
+               return module_finished;
+
+       /* Otherwise, pass request to next module. */
+       verbose(VERB_ALGO, "dns64: pass to next module");
+       return module_wait_module;
+}
+
+/**
+ * Handles the "done" event for a query. We need to analyze the response and
+ * maybe issue a new sub-query for the A record.
+ *
+ * \param qstate A structure representing the state of the query that has just
+ *               received the "pass" event.
+ * \param id     This module's instance ID.
+ *
+ * \return The new state of the query.
+ */
+static enum module_ext_state
+handle_event_moddone(struct module_qstate* qstate, int id)
+{
+    /*
+     * In many cases we have nothing special to do. From most to least common:
+     *
+     *   - An internal query.
+     *   - A query for a record type other than AAAA.
+     *   - CD FLAG was set on querier
+     *   - An AAAA query for which an error was returned.
+     *   - A successful AAAA query with an answer.
+     */
+       if ( (enum dns64_qstate)qstate->minfo[id] == DNS64_INTERNAL_QUERY
+            || qstate->qinfo.qtype != LDNS_RR_TYPE_AAAA
+           || (qstate->query_flags & BIT_CD)
+           || qstate->return_rcode != LDNS_RCODE_NOERROR  
+           || (qstate->return_msg &&
+                   qstate->return_msg->rep &&
+                   reply_find_answer_rrset(&qstate->qinfo,
+                           qstate->return_msg->rep)))
+               return module_finished;
+
+    /* So, this is a AAAA noerror/nodata answer */
+       return generate_type_A_query(qstate, id);
+}
+
+/**
+ * This is the module's main() function. It gets called each time a query
+ * receives an event which we may need to handle. We respond by updating the
+ * state of the query.
+ *
+ * \param qstate   Structure containing the state of the query.
+ * \param event    Event that has just been received.
+ * \param id       This module's instance ID.
+ * \param outbound State of a DNS query on an authoritative server. We never do
+ *                 our own queries ourselves (other modules do it for us), so
+ *                 this is unused.
+ */
+void
+dns64_operate(struct module_qstate* qstate, enum module_ev event, int id,
+               struct outbound_entry* outbound)
+{
+       (void)outbound;
+       verbose(VERB_QUERY, "dns64[module %d] operate: extstate:%s event:%s",
+                       id, strextstate(qstate->ext_state[id]),
+                       strmodulevent(event));
+       log_query_info(VERB_QUERY, "dns64 operate: query", &qstate->qinfo);
+
+       switch(event) {
+               case module_event_new:
+                       /* Tag this query as being new and fall through. */
+                       qstate->minfo[id] = (void*)DNS64_NEW_QUERY;
+               case module_event_pass:
+                       qstate->ext_state[id] = handle_event_pass(qstate, id);
+                       break;
+               case module_event_moddone:
+                       qstate->ext_state[id] = handle_event_moddone(qstate, id);
+                       break;
+               default:
+                       qstate->ext_state[id] = module_finished;
+                       break;
+       }
+}
+
+static void
+dns64_synth_aaaa_data(const struct ub_packed_rrset_key* fk, 
+                     const struct packed_rrset_data* fd, 
+                     struct ub_packed_rrset_key *dk, 
+                     struct packed_rrset_data **dd_out, struct regional *region, 
+                     struct dns64_env* dns64_env )
+{
+       struct packed_rrset_data *dd;
+       size_t i;
+       /*
+        * Create synthesized AAAA RR set data. We need to allocated extra memory
+        * for the RRs themselves. Each RR has a length, TTL, pointer to wireformat
+        * data, 2 bytes of data length, and 16 bytes of IPv6 address.
+        */
+       if(fd->count > RR_COUNT_MAX) {
+               *dd_out = NULL;
+               return; /* integer overflow protection in alloc */
+       }
+       if (!(dd = *dd_out = regional_alloc(region,
+                 sizeof(struct packed_rrset_data)
+                 + fd->count * (sizeof(size_t) + sizeof(time_t) +
+                            sizeof(uint8_t*) + 2 + 16)))) {
+               log_err("out of memory");
+               return;
+       }
+
+       /* Copy attributes from A RR set. */
+       dd->ttl = fd->ttl;
+       dd->count = fd->count;
+       dd->rrsig_count = 0;
+       dd->trust = fd->trust;
+       dd->security = fd->security;
+
+       /*
+        * Synthesize AAAA records. Adjust pointers in structure.
+        */
+       dd->rr_len =
+           (size_t*)((uint8_t*)dd + sizeof(struct packed_rrset_data));
+       dd->rr_data = (uint8_t**)&dd->rr_len[dd->count];
+       dd->rr_ttl = (time_t*)&dd->rr_data[dd->count];
+       for(i = 0; i < fd->count; ++i) {
+               if (fd->rr_len[i] != 6 || fd->rr_data[i][0] != 0
+                   || fd->rr_data[i][1] != 4)
+                       return;
+               dd->rr_len[i] = 18;
+               dd->rr_data[i] =
+                   (uint8_t*)&dd->rr_ttl[dd->count] + 18*i;
+               dd->rr_data[i][0] = 0;
+               dd->rr_data[i][1] = 16;
+               synthesize_aaaa(
+                               ((struct sockaddr_in6*)&dns64_env->prefix_addr)->sin6_addr.s6_addr,
+                               dns64_env->prefix_net, &fd->rr_data[i][2],
+                               &dd->rr_data[i][2] );
+               dd->rr_ttl[i] = fd->rr_ttl[i];
+       }
+
+       /*
+        * Create synthesized AAAA RR set key. This is mostly just bookkeeping,
+        * nothing interesting here.
+        */
+       if(!dk) {
+               log_err("no key");
+               return;
+       }
+
+       dk->rk.dname = (uint8_t*)regional_alloc_init(region,
+                    fk->rk.dname, fk->rk.dname_len);
+
+       if(!dk->rk.dname) {
+               log_err("out of memory");
+               return;
+       }
+
+       dk->rk.type = htons(LDNS_RR_TYPE_AAAA);
+       memset(&dk->entry, 0, sizeof(dk->entry));
+       dk->entry.key = dk;
+       dk->entry.hash = rrset_key_hash(&dk->rk);
+       dk->entry.data = dd;
+
+}
+
+/**
+ * Synthesize an AAAA RR set from an A sub-query's answer and add it to the
+ * original empty response.
+ *
+ * \param id     This module's instance ID.
+ * \param super  Original AAAA query.
+ * \param qstate A query.
+ */
+static void
+dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate)
+{
+       struct dns64_env* dns64_env = (struct dns64_env*)super->env->modinfo[id];
+       struct reply_info *rep, *cp;
+       size_t i, s;
+       struct packed_rrset_data* fd, *dd;
+       struct ub_packed_rrset_key* fk, *dk;
+
+       verbose(VERB_ALGO, "converting A answers to AAAA answers");
+
+       log_assert(super->region);
+       log_assert(qstate->return_msg);
+       log_assert(qstate->return_msg->rep);
+
+       /* If dns64-synthall is enabled, return_msg is not initialized */
+       if(!super->return_msg) {
+               super->return_msg = (struct dns_msg*)regional_alloc(
+                   super->region, sizeof(struct dns_msg));
+               if(!super->return_msg)
+                       return;
+               memset(super->return_msg, 0, sizeof(*super->return_msg));
+               super->return_msg->qinfo = super->qinfo;
+       }
+
+       rep = qstate->return_msg->rep;
+
+       /*
+        * Build the actual reply.
+        */
+       cp = construct_reply_info_base(super->region, rep->flags, rep->qdcount,
+               rep->ttl, rep->prefetch_ttl, rep->an_numrrsets, rep->ns_numrrsets,
+               rep->ar_numrrsets, rep->rrset_count, rep->security);
+       if(!cp)
+               return;
+
+       /* allocate ub_key structures special or not */
+       if(!repinfo_alloc_rrset_keys(cp, super->region)) {
+               return;
+       }
+
+       /* copy everything and replace A by AAAA */
+       for(i=0; i<cp->rrset_count; i++) {
+               fk = rep->rrsets[i];
+               dk = cp->rrsets[i];
+               fd = (struct packed_rrset_data*)fk->entry.data;
+               dk->rk = fk->rk;
+               dk->id = fk->id;
+
+               if(i<rep->an_numrrsets && fk->rk.type == htons(LDNS_RR_TYPE_A)) {
+                       /* also sets dk->entry.hash */
+                       dns64_synth_aaaa_data(fk, fd, dk, &dd, super->region, dns64_env);
+                       if(!dd)
+                               return;
+                       /* Delete negative AAAA record from cache stored by
+                        * the iterator module */
+                       rrset_cache_remove(super->env->rrset_cache, dk->rk.dname, 
+                                          dk->rk.dname_len, LDNS_RR_TYPE_AAAA, 
+                                          LDNS_RR_CLASS_IN, 0);
+               } else {
+                       dk->entry.hash = fk->entry.hash;
+                       dk->rk.dname = (uint8_t*)regional_alloc_init(super->region,
+                               fk->rk.dname, fk->rk.dname_len);
+
+                       if(!dk->rk.dname)
+                               return;
+
+                       s = packed_rrset_sizeof(fd);
+                       dd = (struct packed_rrset_data*)regional_alloc_init(
+                               super->region, fd, s);
+
+                       if(!dd)
+                               return;
+               }
+
+               packed_rrset_ptr_fixup(dd);
+               dk->entry.data = (void*)dd;
+       }
+
+       /* Commit changes. */
+       super->return_msg->rep = cp;
+}
+
+/**
+ * Generate a response for the original IPv6 PTR query based on an IPv4 PTR
+ * sub-query's response.
+ *
+ * \param qstate IPv4 PTR sub-query.
+ * \param super  Original IPv6 PTR query.
+ */
+static void
+dns64_adjust_ptr(struct module_qstate* qstate, struct module_qstate* super)
+{
+    struct ub_packed_rrset_key* answer;
+
+    verbose(VERB_ALGO, "adjusting PTR reply");
+
+    /* Copy the sub-query's reply to the parent. */
+    if (!(super->return_msg = (struct dns_msg*)regional_alloc(super->region,
+                    sizeof(struct dns_msg))))
+        return;
+    super->return_msg->qinfo = super->qinfo;
+    super->return_msg->rep = reply_info_copy(qstate->return_msg->rep, NULL,
+            super->region);
+
+    /*
+     * Adjust the domain name of the answer RR set so that it matches the
+     * initial query's domain name.
+     */
+    answer = reply_find_answer_rrset(&qstate->qinfo, super->return_msg->rep);
+    log_assert(answer);
+    answer->rk.dname = super->qinfo.qname;
+    answer->rk.dname_len = super->qinfo.qname_len;
+}
+
+/**
+ * This function is called when a sub-query finishes to inform the parent query.
+ *
+ * We issue two kinds of sub-queries: PTR and A.
+ *
+ * \param qstate State of the sub-query.
+ * \param id     This module's instance ID.
+ * \param super  State of the super-query.
+ */
+void
+dns64_inform_super(struct module_qstate* qstate, int id,
+               struct module_qstate* super)
+{
+       log_query_info(VERB_ALGO, "dns64: inform_super, sub is",
+                      &qstate->qinfo);
+       log_query_info(VERB_ALGO, "super is", &super->qinfo);
+
+       /*
+        * Signal that the sub-query is finished, no matter whether we are
+        * successful or not. This lets the state machine terminate.
+        */
+       super->minfo[id] = (void*)DNS64_SUBQUERY_FINISHED;
+
+       /* If there is no successful answer, we're done. */
+       if (qstate->return_rcode != LDNS_RCODE_NOERROR
+           || !qstate->return_msg
+           || !qstate->return_msg->rep
+           || !reply_find_answer_rrset(&qstate->qinfo,
+                                       qstate->return_msg->rep))
+               return;
+
+       /* Generate a response suitable for the original query. */
+       if (qstate->qinfo.qtype == LDNS_RR_TYPE_A) {
+               dns64_adjust_a(id, super, qstate);
+       } else {
+               log_assert(qstate->qinfo.qtype == LDNS_RR_TYPE_PTR);
+               dns64_adjust_ptr(qstate, super);
+       }
+
+       /* Store the generated response in cache. */
+       if (!dns_cache_store(super->env, &super->qinfo, super->return_msg->rep,
+           0, 0, 0, NULL, super->query_flags))
+               log_err("out of memory");
+}
+
+/**
+ * Clear module-specific data from query state. Since we do not allocate memory,
+ * it's just a matter of setting a pointer to NULL.
+ *
+ * \param qstate Query state.
+ * \param id     This module's instance ID.
+ */
+void
+dns64_clear(struct module_qstate* qstate, int id)
+{
+    qstate->minfo[id] = NULL;
+}
+
+/**
+ * Returns the amount of global memory that this module uses, not including
+ * per-query data.
+ *
+ * \param env Module environment.
+ * \param id  This module's instance ID.
+ */
+size_t
+dns64_get_mem(struct module_env* env, int id)
+{
+    struct dns64_env* dns64_env = (struct dns64_env*)env->modinfo[id];
+    if (!dns64_env)
+        return 0;
+    return sizeof(*dns64_env);
+}
+
+/**
+ * The dns64 function block.
+ */
+static struct module_func_block dns64_block = {
+       "dns64",
+       &dns64_init, &dns64_deinit, &dns64_operate, &dns64_inform_super,
+       &dns64_clear, &dns64_get_mem
+};
+
+/**
+ * Function for returning the above function block.
+ */
+struct module_func_block *
+dns64_get_funcblock()
+{
+       return &dns64_block;
+}
diff --git a/dns64/dns64.h b/dns64/dns64.h
new file mode 100644 (file)
index 0000000..2f0c01a
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * dns64/dns64.h - DNS64 module
+ *
+ * Copyright (c) 2009, Viagénie. All rights reserved.
+ *
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file contains a module that performs DNS64 query processing.
+ */
+
+#ifndef DNS64_DNS64_H
+#define DNS64_DNS64_H
+#include "util/module.h"
+
+/**
+ * Get the dns64 function block.
+ * @return: function block with function pointers to dns64 methods.
+ */
+struct module_func_block *dns64_get_funcblock(void);
+
+/** dns64 init */
+int dns64_init(struct module_env* env, int id);
+
+/** dns64 deinit */
+void dns64_deinit(struct module_env* env, int id);
+
+/** dns64 operate on a query */
+void dns64_operate(struct module_qstate* qstate, enum module_ev event, int id,
+               struct outbound_entry* outbound);
+
+void dns64_inform_super(struct module_qstate* qstate, int id,
+    struct module_qstate* super);
+
+/** dns64 cleanup query state */
+void dns64_clear(struct module_qstate* qstate, int id);
+
+/** dns64 alloc size routine */
+size_t dns64_get_mem(struct module_env* env, int id);
+
+#endif /* DNS64_DNS64_H */
diff --git a/dnstap/dnstap.c b/dnstap/dnstap.c
new file mode 100644 (file)
index 0000000..b62dc5b
--- /dev/null
@@ -0,0 +1,510 @@
+/* dnstap support for Unbound */
+
+/*
+ * Copyright (c) 2013-2014, Farsight Security, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnstap/dnstap_config.h"
+
+#ifdef USE_DNSTAP
+
+#include "config.h"
+#include <string.h>
+#include <sys/time.h>
+#include "sldns/sbuffer.h"
+#include "util/config_file.h"
+#include "util/net_help.h"
+#include "util/netevent.h"
+#include "util/log.h"
+
+#include <fstrm.h>
+#include <protobuf-c/protobuf-c.h>
+
+#include "dnstap/dnstap.h"
+#include "dnstap/dnstap.pb-c.h"
+
+#define DNSTAP_CONTENT_TYPE            "protobuf:dnstap.Dnstap"
+#define DNSTAP_INITIAL_BUF_SIZE                256
+
+struct dt_msg {
+       void            *buf;
+       size_t          len_buf;
+       Dnstap__Dnstap  d;
+       Dnstap__Message m;
+};
+
+static int
+dt_pack(const Dnstap__Dnstap *d, void **buf, size_t *sz)
+{
+       ProtobufCBufferSimple sbuf;
+
+       memset(&sbuf, 0, sizeof(sbuf));
+       sbuf.base.append = protobuf_c_buffer_simple_append;
+       sbuf.len = 0;
+       sbuf.alloced = DNSTAP_INITIAL_BUF_SIZE;
+       sbuf.data = malloc(sbuf.alloced);
+       if (sbuf.data == NULL)
+               return 0;
+       sbuf.must_free_data = 1;
+
+       *sz = dnstap__dnstap__pack_to_buffer(d, (ProtobufCBuffer *) &sbuf);
+       if (sbuf.data == NULL)
+               return 0;
+       *buf = sbuf.data;
+
+       return 1;
+}
+
+static void
+dt_send(const struct dt_env *env, void *buf, size_t len_buf)
+{
+       fstrm_res res;
+       if (!buf)
+               return;
+       res = fstrm_iothr_submit(env->iothr, env->ioq, buf, len_buf,
+                                fstrm_free_wrapper, NULL);
+       if (res != fstrm_res_success)
+               free(buf);
+}
+
+static void
+dt_msg_init(const struct dt_env *env,
+           struct dt_msg *dm,
+           Dnstap__Message__Type mtype)
+{
+       memset(dm, 0, sizeof(*dm));
+       dm->d.base.descriptor = &dnstap__dnstap__descriptor;
+       dm->m.base.descriptor = &dnstap__message__descriptor;
+       dm->d.type = DNSTAP__DNSTAP__TYPE__MESSAGE;
+       dm->d.message = &dm->m;
+       dm->m.type = mtype;
+       if (env->identity != NULL) {
+               dm->d.identity.data = (uint8_t *) env->identity;
+               dm->d.identity.len = (size_t) env->len_identity;
+               dm->d.has_identity = 1;
+       }
+       if (env->version != NULL) {
+               dm->d.version.data = (uint8_t *) env->version;
+               dm->d.version.len = (size_t) env->len_version;
+               dm->d.has_version = 1;
+       }
+}
+
+struct dt_env *
+dt_create(const char *socket_path, unsigned num_workers)
+{
+       fstrm_res res;
+       struct dt_env *env;
+       struct fstrm_iothr_options *fopt;
+       struct fstrm_unix_writer_options *fuwopt;
+       struct fstrm_writer *fw;
+       struct fstrm_writer_options *fwopt;
+
+       verbose(VERB_OPS, "opening dnstap socket %s", socket_path);
+       log_assert(socket_path != NULL);
+       log_assert(num_workers > 0);
+
+       env = (struct dt_env *) calloc(1, sizeof(struct dt_env));
+       if (!env)
+               return NULL;
+
+       fwopt = fstrm_writer_options_init();
+       res = fstrm_writer_options_add_content_type(fwopt,
+               DNSTAP_CONTENT_TYPE, sizeof(DNSTAP_CONTENT_TYPE) - 1);
+       log_assert(res == fstrm_res_success);
+
+       fuwopt = fstrm_unix_writer_options_init();
+       fstrm_unix_writer_options_set_socket_path(fuwopt, socket_path);
+
+       fw = fstrm_unix_writer_init(fuwopt, fwopt);
+       log_assert(fw != NULL);
+
+       fopt = fstrm_iothr_options_init();
+       fstrm_iothr_options_set_num_input_queues(fopt, num_workers);
+       env->iothr = fstrm_iothr_init(fopt, &fw);
+       if (env->iothr == NULL) {
+               verbose(VERB_DETAIL, "dt_create: fstrm_iothr_init() failed");
+               fstrm_writer_destroy(&fw);
+               free(env);
+               env = NULL;
+       }
+       fstrm_iothr_options_destroy(&fopt);
+       fstrm_unix_writer_options_destroy(&fuwopt);
+       fstrm_writer_options_destroy(&fwopt);
+
+       return env;
+}
+
+static void
+dt_apply_identity(struct dt_env *env, struct config_file *cfg)
+{
+       char buf[MAXHOSTNAMELEN+1];
+       if (!cfg->dnstap_send_identity)
+               return;
+       free(env->identity);
+       if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) {
+               if (gethostname(buf, MAXHOSTNAMELEN) == 0) {
+                       buf[MAXHOSTNAMELEN] = 0;
+                       env->identity = strdup(buf);
+               } else {
+                       fatal_exit("dt_apply_identity: gethostname() failed");
+               }
+       } else {
+               env->identity = strdup(cfg->dnstap_identity);
+       }
+       if (env->identity == NULL)
+               fatal_exit("dt_apply_identity: strdup() failed");
+       env->len_identity = (unsigned int)strlen(env->identity);
+       verbose(VERB_OPS, "dnstap identity field set to \"%s\"",
+               env->identity);
+}
+
+static void
+dt_apply_version(struct dt_env *env, struct config_file *cfg)
+{
+       if (!cfg->dnstap_send_version)
+               return;
+       free(env->version);
+       if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0)
+               env->version = strdup(PACKAGE_STRING);
+       else
+               env->version = strdup(cfg->dnstap_version);
+       if (env->version == NULL)
+               fatal_exit("dt_apply_version: strdup() failed");
+       env->len_version = (unsigned int)strlen(env->version);
+       verbose(VERB_OPS, "dnstap version field set to \"%s\"",
+               env->version);
+}
+
+void
+dt_apply_cfg(struct dt_env *env, struct config_file *cfg)
+{
+       if (!cfg->dnstap)
+               return;
+
+       dt_apply_identity(env, cfg);
+       dt_apply_version(env, cfg);
+       if ((env->log_resolver_query_messages = (unsigned int)
+            cfg->dnstap_log_resolver_query_messages))
+       {
+               verbose(VERB_OPS, "dnstap Message/RESOLVER_QUERY enabled");
+       }
+       if ((env->log_resolver_response_messages = (unsigned int)
+            cfg->dnstap_log_resolver_response_messages))
+       {
+               verbose(VERB_OPS, "dnstap Message/RESOLVER_RESPONSE enabled");
+       }
+       if ((env->log_client_query_messages = (unsigned int)
+            cfg->dnstap_log_client_query_messages))
+       {
+               verbose(VERB_OPS, "dnstap Message/CLIENT_QUERY enabled");
+       }
+       if ((env->log_client_response_messages = (unsigned int)
+            cfg->dnstap_log_client_response_messages))
+       {
+               verbose(VERB_OPS, "dnstap Message/CLIENT_RESPONSE enabled");
+       }
+       if ((env->log_forwarder_query_messages = (unsigned int)
+            cfg->dnstap_log_forwarder_query_messages))
+       {
+               verbose(VERB_OPS, "dnstap Message/FORWARDER_QUERY enabled");
+       }
+       if ((env->log_forwarder_response_messages = (unsigned int)
+            cfg->dnstap_log_forwarder_response_messages))
+       {
+               verbose(VERB_OPS, "dnstap Message/FORWARDER_RESPONSE enabled");
+       }
+}
+
+int
+dt_init(struct dt_env *env)
+{
+       env->ioq = fstrm_iothr_get_input_queue(env->iothr);
+       if (env->ioq == NULL)
+               return 0;
+       return 1;
+}
+
+void
+dt_delete(struct dt_env *env)
+{
+       if (!env)
+               return;
+       verbose(VERB_OPS, "closing dnstap socket");
+       fstrm_iothr_destroy(&env->iothr);
+       free(env->identity);
+       free(env->version);
+       free(env);
+}
+
+static void
+dt_fill_timeval(const struct timeval *tv,
+               uint64_t *time_sec, protobuf_c_boolean *has_time_sec,
+               uint32_t *time_nsec, protobuf_c_boolean *has_time_nsec)
+{
+#ifndef S_SPLINT_S
+       *time_sec = tv->tv_sec;
+       *time_nsec = tv->tv_usec * 1000;
+#endif
+       *has_time_sec = 1;
+       *has_time_nsec = 1;
+}
+
+static void
+dt_fill_buffer(sldns_buffer *b, ProtobufCBinaryData *p, protobuf_c_boolean *has)
+{
+       log_assert(b != NULL);
+       p->len = sldns_buffer_limit(b);
+       p->data = sldns_buffer_begin(b);
+       *has = 1;
+}
+
+static void
+dt_msg_fill_net(struct dt_msg *dm,
+               struct sockaddr_storage *ss,
+               enum comm_point_type cptype,
+               ProtobufCBinaryData *addr, protobuf_c_boolean *has_addr,
+               uint32_t *port, protobuf_c_boolean *has_port)
+{
+       log_assert(ss->ss_family == AF_INET6 || ss->ss_family == AF_INET);
+       if (ss->ss_family == AF_INET6) {
+               struct sockaddr_in6 *s = (struct sockaddr_in6 *) ss;
+
+               /* socket_family */
+               dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET6;
+               dm->m.has_socket_family = 1;
+
+               /* addr: query_address or response_address */
+               addr->data = s->sin6_addr.s6_addr;
+               addr->len = 16; /* IPv6 */
+               *has_addr = 1;
+
+               /* port: query_port or response_port */
+               *port = ntohs(s->sin6_port);
+               *has_port = 1;
+       } else if (ss->ss_family == AF_INET) {
+               struct sockaddr_in *s = (struct sockaddr_in *) ss;
+
+               /* socket_family */
+               dm->m.socket_family = DNSTAP__SOCKET_FAMILY__INET;
+               dm->m.has_socket_family = 1;
+
+               /* addr: query_address or response_address */
+               addr->data = (uint8_t *) &s->sin_addr.s_addr;
+               addr->len = 4; /* IPv4 */
+               *has_addr = 1;
+
+               /* port: query_port or response_port */
+               *port = ntohs(s->sin_port);
+               *has_port = 1;
+       }
+
+       log_assert(cptype == comm_udp || cptype == comm_tcp);
+       if (cptype == comm_udp) {
+               /* socket_protocol */
+               dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__UDP;
+               dm->m.has_socket_protocol = 1;
+       } else if (cptype == comm_tcp) {
+               /* socket_protocol */
+               dm->m.socket_protocol = DNSTAP__SOCKET_PROTOCOL__TCP;
+               dm->m.has_socket_protocol = 1;
+       }
+}
+
+void
+dt_msg_send_client_query(struct dt_env *env,
+                        struct sockaddr_storage *qsock,
+                        enum comm_point_type cptype,
+                        sldns_buffer *qmsg)
+{
+       struct dt_msg dm;
+       struct timeval qtime;
+
+       gettimeofday(&qtime, NULL);
+
+       /* type */
+       dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__CLIENT_QUERY);
+
+       /* query_time */
+       dt_fill_timeval(&qtime,
+                       &dm.m.query_time_sec, &dm.m.has_query_time_sec,
+                       &dm.m.query_time_nsec, &dm.m.has_query_time_nsec);
+
+       /* query_message */
+       dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message);
+
+       /* socket_family, socket_protocol, query_address, query_port */
+       log_assert(cptype == comm_udp || cptype == comm_tcp);
+       dt_msg_fill_net(&dm, qsock, cptype,
+                       &dm.m.query_address, &dm.m.has_query_address,
+                       &dm.m.query_port, &dm.m.has_query_port);
+
+       if (dt_pack(&dm.d, &dm.buf, &dm.len_buf))
+               dt_send(env, dm.buf, dm.len_buf);
+}
+
+void
+dt_msg_send_client_response(struct dt_env *env,
+                           struct sockaddr_storage *qsock,
+                           enum comm_point_type cptype,
+                           sldns_buffer *rmsg)
+{
+       struct dt_msg dm;
+       struct timeval rtime;
+
+       gettimeofday(&rtime, NULL);
+
+       /* type */
+       dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__CLIENT_RESPONSE);
+
+       /* response_time */
+       dt_fill_timeval(&rtime,
+                       &dm.m.response_time_sec, &dm.m.has_response_time_sec,
+                       &dm.m.response_time_nsec, &dm.m.has_response_time_nsec);
+
+       /* response_message */
+       dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message);
+
+       /* socket_family, socket_protocol, query_address, query_port */
+       log_assert(cptype == comm_udp || cptype == comm_tcp);
+       dt_msg_fill_net(&dm, qsock, cptype,
+                       &dm.m.query_address, &dm.m.has_query_address,
+                       &dm.m.query_port, &dm.m.has_query_port);
+
+       if (dt_pack(&dm.d, &dm.buf, &dm.len_buf))
+               dt_send(env, dm.buf, dm.len_buf);
+}
+
+void
+dt_msg_send_outside_query(struct dt_env *env,
+                         struct sockaddr_storage *rsock,
+                         enum comm_point_type cptype,
+                         uint8_t *zone, size_t zone_len,
+                         sldns_buffer *qmsg)
+{
+       struct dt_msg dm;
+       struct timeval qtime;
+       uint16_t qflags;
+
+       gettimeofday(&qtime, NULL);
+       qflags = sldns_buffer_read_u16_at(qmsg, 2);
+
+       /* type */
+       if (qflags & BIT_RD) {
+               if (!env->log_forwarder_query_messages)
+                       return;
+               dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY);
+       } else {
+               if (!env->log_resolver_query_messages)
+                       return;
+               dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY);
+       }
+
+       /* query_zone */
+       dm.m.query_zone.data = zone;
+       dm.m.query_zone.len = zone_len;
+       dm.m.has_query_zone = 1;
+
+       /* query_time_sec, query_time_nsec */
+       dt_fill_timeval(&qtime,
+                       &dm.m.query_time_sec, &dm.m.has_query_time_sec,
+                       &dm.m.query_time_nsec, &dm.m.has_query_time_nsec);
+
+       /* query_message */
+       dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message);
+
+       /* socket_family, socket_protocol, response_address, response_port */
+       log_assert(cptype == comm_udp || cptype == comm_tcp);
+       dt_msg_fill_net(&dm, rsock, cptype,
+                       &dm.m.response_address, &dm.m.has_response_address,
+                       &dm.m.response_port, &dm.m.has_response_port);
+
+       if (dt_pack(&dm.d, &dm.buf, &dm.len_buf))
+               dt_send(env, dm.buf, dm.len_buf);
+}
+
+void
+dt_msg_send_outside_response(struct dt_env *env,
+                            struct sockaddr_storage *rsock,
+                            enum comm_point_type cptype,
+                            uint8_t *zone, size_t zone_len,
+                            uint8_t *qbuf, size_t qbuf_len,
+                            const struct timeval *qtime,
+                            const struct timeval *rtime,
+                            sldns_buffer *rmsg)
+{
+       struct dt_msg dm;
+       uint16_t qflags;
+
+       log_assert(qbuf_len >= sizeof(qflags));
+       memcpy(&qflags, qbuf, sizeof(qflags));
+       qflags = ntohs(qflags);
+
+       /* type */
+       if (qflags & BIT_RD) {
+               if (!env->log_forwarder_response_messages)
+                       return;
+               dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_RESPONSE);
+       } else {
+               if (!env->log_resolver_query_messages)
+                       return;
+               dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__RESOLVER_RESPONSE);
+       }
+
+       /* query_zone */
+       dm.m.query_zone.data = zone;
+       dm.m.query_zone.len = zone_len;
+       dm.m.has_query_zone = 1;
+
+       /* query_time_sec, query_time_nsec */
+       dt_fill_timeval(qtime,
+                       &dm.m.query_time_sec, &dm.m.has_query_time_sec,
+                       &dm.m.query_time_nsec, &dm.m.has_query_time_nsec);
+
+       /* response_time_sec, response_time_nsec */
+       dt_fill_timeval(rtime,
+                       &dm.m.response_time_sec, &dm.m.has_response_time_sec,
+                       &dm.m.response_time_nsec, &dm.m.has_response_time_nsec);
+
+       /* response_message */
+       dt_fill_buffer(rmsg, &dm.m.response_message, &dm.m.has_response_message);
+
+       /* socket_family, socket_protocol, response_address, response_port */
+       log_assert(cptype == comm_udp || cptype == comm_tcp);
+       dt_msg_fill_net(&dm, rsock, cptype,
+                       &dm.m.response_address, &dm.m.has_response_address,
+                       &dm.m.response_port, &dm.m.has_response_port);
+
+       if (dt_pack(&dm.d, &dm.buf, &dm.len_buf))
+               dt_send(env, dm.buf, dm.len_buf);
+}
+
+#endif /* USE_DNSTAP */
diff --git a/dnstap/dnstap.h b/dnstap/dnstap.h
new file mode 100644 (file)
index 0000000..0103c1c
--- /dev/null
@@ -0,0 +1,188 @@
+/* dnstap support for Unbound */
+
+/*
+ * Copyright (c) 2013-2014, Farsight Security, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UNBOUND_DNSTAP_H
+#define UNBOUND_DNSTAP_H
+
+#include "dnstap/dnstap_config.h"
+
+#ifdef USE_DNSTAP
+
+struct config_file;
+struct fstrm_io;
+struct fstrm_queue;
+struct sldns_buffer;
+
+struct dt_env {
+       /** dnstap I/O thread */
+       struct fstrm_iothr *iothr;
+
+       /** dnstap I/O thread input queue */
+       struct fstrm_iothr_queue *ioq;
+
+       /** dnstap "identity" field, NULL if disabled */
+       char *identity;
+
+       /** dnstap "version" field, NULL if disabled */
+       char *version;
+
+       /** length of "identity" field */
+       unsigned len_identity;
+
+       /** length of "version" field */
+       unsigned len_version;
+
+       /** whether to log Message/RESOLVER_QUERY */
+       unsigned log_resolver_query_messages : 1;
+       /** whether to log Message/RESOLVER_RESPONSE */
+       unsigned log_resolver_response_messages : 1;
+       /** whether to log Message/CLIENT_QUERY */
+       unsigned log_client_query_messages : 1;
+       /** whether to log Message/CLIENT_RESPONSE */
+       unsigned log_client_response_messages : 1;
+       /** whether to log Message/FORWARDER_QUERY */
+       unsigned log_forwarder_query_messages : 1;
+       /** whether to log Message/FORWARDER_RESPONSE */
+       unsigned log_forwarder_response_messages : 1;
+};
+
+/**
+ * Create dnstap environment object. Afterwards, call dt_apply_cfg() to fill in
+ * the config variables and dt_init() to fill in the per-worker state. Each
+ * worker needs a copy of this object but with its own I/O queue (the fq field
+ * of the structure) to ensure lock-free access to its own per-worker circular
+ * queue.  Duplicate the environment object if more than one worker needs to
+ * share access to the dnstap I/O socket.
+ * @param socket_path: path to dnstap logging socket, must be non-NULL.
+ * @param num_workers: number of worker threads, must be > 0.
+ * @return dt_env object, NULL on failure.
+ */
+struct dt_env *
+dt_create(const char *socket_path, unsigned num_workers);
+
+/**
+ * Apply config settings.
+ * @param env: dnstap environment object.
+ * @param cfg: new config settings.
+ */
+void
+dt_apply_cfg(struct dt_env *env, struct config_file *cfg);
+
+/**
+ * Initialize per-worker state in dnstap environment object.
+ * @param env: dnstap environment object to initialize, created with dt_create().
+ * @return: true on success, false on failure.
+ */
+int
+dt_init(struct dt_env *env);
+
+/**
+ * Delete dnstap environment object. Closes dnstap I/O socket and deletes all
+ * per-worker I/O queues.
+ */
+void
+dt_delete(struct dt_env *env);
+
+/**
+ * Create and send a new dnstap "Message" event of type CLIENT_QUERY.
+ * @param env: dnstap environment object.
+ * @param qsock: address/port of client.
+ * @param cptype: comm_udp or comm_tcp.
+ * @param qmsg: query message.
+ */
+void
+dt_msg_send_client_query(struct dt_env *env,
+                        struct sockaddr_storage *qsock,
+                        enum comm_point_type cptype,
+                        struct sldns_buffer *qmsg);
+
+/**
+ * Create and send a new dnstap "Message" event of type CLIENT_RESPONSE.
+ * @param env: dnstap environment object.
+ * @param qsock: address/port of client.
+ * @param cptype: comm_udp or comm_tcp.
+ * @param rmsg: response message.
+ */
+void
+dt_msg_send_client_response(struct dt_env *env,
+                           struct sockaddr_storage *qsock,
+                           enum comm_point_type cptype,
+                           struct sldns_buffer *rmsg);
+
+/**
+ * Create and send a new dnstap "Message" event of type RESOLVER_QUERY or
+ * FORWARDER_QUERY. The type used is dependent on the value of the RD bit
+ * in the query header.
+ * @param env: dnstap environment object.
+ * @param rsock: address/port of server the query is being sent to.
+ * @param cptype: comm_udp or comm_tcp.
+ * @param zone: query zone.
+ * @param zone_len: length of zone.
+ * @param qmsg: query message.
+ */
+void
+dt_msg_send_outside_query(struct dt_env *env,
+                         struct sockaddr_storage *rsock,
+                         enum comm_point_type cptype,
+                         uint8_t *zone, size_t zone_len,
+                         struct sldns_buffer *qmsg);
+
+/**
+ * Create and send a new dnstap "Message" event of type RESOLVER_RESPONSE or
+ * FORWARDER_RESPONSE. The type used is dependent on the value of the RD bit
+ * in the query header.
+ * @param env: dnstap environment object.
+ * @param rsock: address/port of server the response was received from.
+ * @param cptype: comm_udp or comm_tcp.
+ * @param zone: query zone.
+ * @param zone_len: length of zone.
+ * @param qbuf: outside_network's qbuf key.
+ * @param qbuf_len: length of outside_network's qbuf key.
+ * @param qtime: time query message was sent.
+ * @param rtime: time response message was sent.
+ * @param rmsg: response message.
+ */
+void
+dt_msg_send_outside_response(struct dt_env *env,
+                            struct sockaddr_storage *rsock,
+                            enum comm_point_type cptype,
+                            uint8_t *zone, size_t zone_len,
+                            uint8_t *qbuf, size_t qbuf_len,
+                            const struct timeval *qtime,
+                            const struct timeval *rtime,
+                            struct sldns_buffer *rmsg);
+
+#endif /* USE_DNSTAP */
+
+#endif /* UNBOUND_DNSTAP_H */
diff --git a/dnstap/dnstap.m4 b/dnstap/dnstap.m4
new file mode 100644 (file)
index 0000000..5b78b3e
--- /dev/null
@@ -0,0 +1,56 @@
+# dnstap.m4
+
+# dt_DNSTAP(default_dnstap_socket_path, [action-if-true], [action-if-false])
+# --------------------------------------------------------------------------
+# Check for required dnstap libraries and add dnstap configure args.
+AC_DEFUN([dt_DNSTAP],
+[
+  AC_ARG_ENABLE([dnstap],
+    AS_HELP_STRING([--enable-dnstap],
+                   [Enable dnstap support (requires fstrm, protobuf-c)]),
+    [opt_dnstap=$enableval], [opt_dnstap=no])
+
+  AC_ARG_WITH([dnstap-socket-path],
+    AS_HELP_STRING([--with-dnstap-socket-path=pathname],
+                   [set default dnstap socket path]),
+    [opt_dnstap_socket_path=$withval], [opt_dnstap_socket_path="$1"])
+
+  if test "x$opt_dnstap" != "xno"; then
+    AC_PATH_PROG([PROTOC_C], [protoc-c])
+    if test -z "$PROTOC_C"; then
+      AC_MSG_ERROR([The protoc-c program was not found. Please install protobuf-c!])
+    fi
+    AC_ARG_WITH([protobuf-c], AC_HELP_STRING([--with-protobuf-c=path],
+       [Path where protobuf-c is installed, for dnstap]), [
+         # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0
+         if test -f $withval/include/google/protobuf-c/protobuf-c.h; then
+           CFLAGS="$CFLAGS -I$withval/include/google"
+         else
+           CFLAGS="$CFLAGS -I$withval/include"
+         fi
+         LDFLAGS="$LDFLAGS -L$withval/lib"
+       ], [
+         # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0
+         if test -f /usr/include/google/protobuf-c/protobuf-c.h; then
+           CFLAGS="$CFLAGS -I/usr/include/google"
+         else
+           if test -f /usr/local/include/google/protobuf-c/protobuf-c.h; then
+             CFLAGS="$CFLAGS -I/usr/local/include/google"
+             LDFLAGS="$LDFLAGS -L/usr/local/lib"
+           fi
+         fi
+    ])
+    AC_ARG_WITH([libfstrm], AC_HELP_STRING([--with-libfstrm=path],
+       [Path where libfstrm is installed, for dnstap]), [
+       CFLAGS="$CFLAGS -I$withval/include"
+       LDFLAGS="$LDFLAGS -L$withval/lib"
+    ])
+    AC_SEARCH_LIBS([fstrm_iothr_init], [fstrm], [],
+      AC_MSG_ERROR([The fstrm library was not found. Please install fstrm!]))
+    AC_SEARCH_LIBS([protobuf_c_message_pack], [protobuf-c], [],
+      AC_MSG_ERROR([The protobuf-c library was not found. Please install protobuf-c!]))
+    $2
+  else
+    $3
+  fi
+])
diff --git a/dnstap/dnstap.proto b/dnstap/dnstap.proto
new file mode 100644 (file)
index 0000000..3504d99
--- /dev/null
@@ -0,0 +1,262 @@
+// dnstap: flexible, structured event replication format for DNS software
+//
+// This file contains the protobuf schemas for the "dnstap" structured event
+// replication format for DNS software.
+
+// Written in 2013-2014 by Farsight Security, Inc.
+//
+// To the extent possible under law, the author(s) have dedicated all
+// copyright and related and neighboring rights to this file to the public
+// domain worldwide. This file is distributed without any warranty.
+//
+// You should have received a copy of the CC0 Public Domain Dedication along
+// with this file. If not, see:
+//
+// <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+package dnstap;
+
+// "Dnstap": this is the top-level dnstap type, which is a "union" type that
+// contains other kinds of dnstap payloads, although currently only one type
+// of dnstap payload is defined.
+// See: https://developers.google.com/protocol-buffers/docs/techniques#union
+message Dnstap {
+    // DNS server identity.
+    // If enabled, this is the identity string of the DNS server which generated
+    // this message. Typically this would be the same string as returned by an
+    // "NSID" (RFC 5001) query.
+    optional bytes      identity = 1;
+
+    // DNS server version.
+    // If enabled, this is the version string of the DNS server which generated
+    // this message. Typically this would be the same string as returned by a
+    // "version.bind" query.
+    optional bytes      version = 2;
+
+    // Extra data for this payload.
+    // This field can be used for adding an arbitrary byte-string annotation to
+    // the payload. No encoding or interpretation is applied or enforced.
+    optional bytes      extra = 3;
+
+    // Identifies which field below is filled in.
+    enum Type {
+        MESSAGE = 1;
+    }
+    required Type       type = 15;
+
+    // One of the following will be filled in.
+    optional Message    message = 14;
+}
+
+// SocketFamily: the network protocol family of a socket. This specifies how
+// to interpret "network address" fields.
+enum SocketFamily {
+    INET = 1;   // IPv4 (RFC 791)
+    INET6 = 2;  // IPv6 (RFC 2460)
+}
+
+// SocketProtocol: the transport protocol of a socket. This specifies how to
+// interpret "transport port" fields.
+enum SocketProtocol {
+    UDP = 1;    // User Datagram Protocol (RFC 768)
+    TCP = 2;    // Transmission Control Protocol (RFC 793)
+}
+
+// Message: a wire-format (RFC 1035 section 4) DNS message and associated
+// metadata. Applications generating "Message" payloads should follow
+// certain requirements based on the MessageType, see below.
+message Message {
+
+    // There are eight types of "Message" defined that correspond to the
+    // four arrows in the following diagram, slightly modified from RFC 1035
+    // section 2:
+
+    //    +---------+               +----------+           +--------+
+    //    |         |     query     |          |   query   |        |
+    //    | Stub    |-SQ--------CQ->| Recursive|-RQ----AQ->| Auth.  |
+    //    | Resolver|               | Server   |           | Name   |
+    //    |         |<-SR--------CR-|          |<-RR----AR-| Server |
+    //    +---------+    response   |          |  response |        |
+    //                              +----------+           +--------+
+
+    // Each arrow has two Type values each, one for each "end" of each arrow,
+    // because these are considered to be distinct events. Each end of each
+    // arrow on the diagram above has been marked with a two-letter Type
+    // mnemonic. Clockwise from upper left, these mnemonic values are:
+    //
+    //   SQ:        STUB_QUERY
+    //   CQ:      CLIENT_QUERY
+    //   RQ:    RESOLVER_QUERY
+    //   AQ:        AUTH_QUERY
+    //   AR:        AUTH_RESPONSE
+    //   RR:    RESOLVER_RESPONSE
+    //   CR:      CLIENT_RESPONSE
+    //   SR:        STUB_RESPONSE
+
+    // Two additional types of "Message" have been defined for the
+    // "forwarding" case where an upstream DNS server is responsible for
+    // further recursion. These are not shown on the diagram above, but have
+    // the following mnemonic values:
+
+    //   FQ:   FORWARDER_QUERY
+    //   FR:   FORWARDER_RESPONSE
+
+    // The "Message" Type values are defined below.
+
+    enum Type {
+        // AUTH_QUERY is a DNS query message received from a resolver by an
+        // authoritative name server, from the perspective of the authorative
+        // name server.
+        AUTH_QUERY = 1;
+
+        // AUTH_RESPONSE is a DNS response message sent from an authoritative
+        // name server to a resolver, from the perspective of the authoritative
+        // name server.
+        AUTH_RESPONSE = 2;
+
+        // RESOLVER_QUERY is a DNS query message sent from a resolver to an
+        // authoritative name server, from the perspective of the resolver.
+        // Resolvers typically clear the RD (recursion desired) bit when
+        // sending queries.
+        RESOLVER_QUERY = 3;
+
+        // RESOLVER_RESPONSE is a DNS response message received from an
+        // authoritative name server by a resolver, from the perspective of
+        // the resolver.
+        RESOLVER_RESPONSE = 4;
+
+        // CLIENT_QUERY is a DNS query message sent from a client to a DNS
+        // server which is expected to perform further recursion, from the
+        // perspective of the DNS server. The client may be a stub resolver or
+        // forwarder or some other type of software which typically sets the RD
+        // (recursion desired) bit when querying the DNS server. The DNS server
+        // may be a simple forwarding proxy or it may be a full recursive
+        // resolver.
+        CLIENT_QUERY = 5;
+
+        // CLIENT_RESPONSE is a DNS response message sent from a DNS server to
+        // a client, from the perspective of the DNS server. The DNS server
+        // typically sets the RA (recursion available) bit when responding.
+        CLIENT_RESPONSE = 6;
+
+        // FORWARDER_QUERY is a DNS query message sent from a downstream DNS
+        // server to an upstream DNS server which is expected to perform
+        // further recursion, from the perspective of the downstream DNS
+        // server.
+        FORWARDER_QUERY = 7;
+
+        // FORWARDER_RESPONSE is a DNS response message sent from an upstream
+        // DNS server performing recursion to a downstream DNS server, from the
+        // perspective of the downstream DNS server.
+        FORWARDER_RESPONSE = 8;
+
+        // STUB_QUERY is a DNS query message sent from a stub resolver to a DNS
+        // server, from the perspective of the stub resolver.
+        STUB_QUERY = 9;
+
+        // STUB_RESPONSE is a DNS response message sent from a DNS server to a
+        // stub resolver, from the perspective of the stub resolver.
+        STUB_RESPONSE = 10;
+    }
+
+    // One of the Type values described above.
+    required Type               type = 1;
+
+    // One of the SocketFamily values described above.
+    optional SocketFamily       socket_family = 2;
+
+    // One of the SocketProtocol values described above.
+    optional SocketProtocol     socket_protocol = 3;
+
+    // The network address of the message initiator.
+    // For SocketFamily INET, this field is 4 octets (IPv4 address).
+    // For SocketFamily INET6, this field is 16 octets (IPv6 address).
+    optional bytes              query_address = 4;
+
+    // The network address of the message responder.
+    // For SocketFamily INET, this field is 4 octets (IPv4 address).
+    // For SocketFamily INET6, this field is 16 octets (IPv6 address).
+    optional bytes              response_address = 5;
+
+    // The transport port of the message initiator.
+    // This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
+    optional uint32             query_port = 6;
+
+    // The transport port of the message responder.
+    // This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
+    optional uint32             response_port = 7;
+
+    // The time at which the DNS query message was sent or received, depending
+    // on whether this is an AUTH_QUERY, RESOLVER_QUERY, or CLIENT_QUERY.
+    // This is the number of seconds since the UNIX epoch.
+    optional uint64             query_time_sec = 8;
+
+    // The time at which the DNS query message was sent or received.
+    // This is the seconds fraction, expressed as a count of nanoseconds.
+    optional fixed32            query_time_nsec = 9;
+
+    // The initiator's original wire-format DNS query message, verbatim.
+    optional bytes              query_message = 10;
+
+    // The "zone" or "bailiwick" pertaining to the DNS query message.
+    // This is a wire-format DNS domain name.
+    optional bytes              query_zone = 11;
+
+    // The time at which the DNS response message was sent or received,
+    // depending on whether this is an AUTH_RESPONSE, RESOLVER_RESPONSE, or
+    // CLIENT_RESPONSE.
+    // This is the number of seconds since the UNIX epoch.
+    optional uint64             response_time_sec = 12;
+
+    // The time at which the DNS response message was sent or received.
+    // This is the seconds fraction, expressed as a count of nanoseconds.
+    optional fixed32            response_time_nsec = 13;
+
+    // The responder's original wire-format DNS response message, verbatim.
+    optional bytes              response_message = 14;
+}
+
+// All fields except for 'type' in the Message schema are optional.
+// It is recommended that at least the following fields be filled in for
+// particular types of Messages.
+
+// AUTH_QUERY:
+//      socket_family, socket_protocol
+//      query_address, query_port
+//      query_message
+//      query_time_sec, query_time_nsec
+
+// AUTH_RESPONSE:
+//      socket_family, socket_protocol
+//      query_address, query_port
+//      query_time_sec, query_time_nsec
+//      response_message
+//      response_time_sec, response_time_nsec
+
+// RESOLVER_QUERY:
+//      socket_family, socket_protocol
+//      query_name, query_type, query_class
+//      query_message
+//      query_time_sec, query_time_nsec
+//      query_zone
+//      response_address, response_port
+
+// RESOLVER_RESPONSE:
+//      socket_family, socket_protocol
+//      query_name, query_type, query_class
+//      query_time_sec, query_time_nsec
+//      query_zone
+//      response_address, response_port
+//      response_message
+//      response_time_sec, response_time_nsec
+
+// CLIENT_QUERY:
+//      socket_family, socket_protocol
+//      query_message
+//      query_time_sec, query_time_nsec
+
+// CLIENT_RESPONSE:
+//      socket_family, socket_protocol
+//      query_time_sec, query_time_nsec
+//      response_message
+//      response_time_sec, response_time_nsec
diff --git a/dnstap/dnstap_config.h.in b/dnstap/dnstap_config.h.in
new file mode 100644 (file)
index 0000000..c9f7489
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef UNBOUND_DNSTAP_CONFIG_H
+#define UNBOUND_DNSTAP_CONFIG_H
+
+/*
+ * Process this file (dnstap_config.h.in) with AC_CONFIG_FILES to generate
+ * dnstap_config.h.
+ *
+ * This file exists so that USE_DNSTAP can be used without including config.h.
+ */
+
+#if @ENABLE_DNSTAP@ /* ENABLE_DNSTAP */
+# ifndef USE_DNSTAP
+#  define USE_DNSTAP 1
+# endif
+#endif
+
+#endif /* UNBOUND_DNSTAP_CONFIG_H */
diff --git a/doc/README.DNS64 b/doc/README.DNS64
new file mode 100644 (file)
index 0000000..49446ac
--- /dev/null
@@ -0,0 +1,30 @@
+The DNS64 code was written by Viagenie, 2009, by Simon Perrault as part
+of the Ecdysis project.  The code is copyright by them, and has the BSD
+license (see the dns64/dns64.c file).
+
+To enable DNS64 functionality in Unbound, two directives in unbound.conf must
+be edited:
+
+1. The "module-config" directive must start with "dns64". For example:
+
+    module-config: "dns64 validator iterator"
+
+If you're not using DNSSEC then you may remove "validator".
+
+2. The "dns64-prefix" directive indicates your DNS64 prefix. For example:
+
+    dns64-prefix: 64:FF9B::/96
+
+The prefix must be a /96 or shorter.
+
+To test that things are working right, perform a query against Unbound for a
+domain name for which no AAAA record exists. You should see a AAAA record in
+the answer section. The corresponding IPv6 address will be inside the DNS64
+prefix. For example:
+
+    $ unbound -c unbound.conf
+    $ dig @localhost jazz-v4.viagenie.ca aaaa
+    [...]
+    ;; ANSWER SECTION:
+    jazz-v4.viagenie.ca.        86400   IN      AAAA    64:ff9b::ce7b:1f02
+
diff --git a/libunbound/python/file_py3.i b/libunbound/python/file_py3.i
new file mode 100644 (file)
index 0000000..5d8b5a2
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * file_py3.i: Typemaps for FILE* for Python 3
+ *
+ * Copyright (c) 2011, Karel Slany (karel.slany AT nic.cz)
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the organization nor the names of its
+ *       contributors may be used to endorse or promote products derived from this
+ *       software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%{
+#include <unistd.h>
+#include <fcntl.h>
+%}
+
+%types(FILE *);
+
+//#define SWIG_FILE3_DEBUG
+
+/* converts basic file descriptor flags onto a string */
+%fragment("fdfl_to_str", "header") {
+const char *
+fdfl_to_str(int fdfl) {
+
+  static const char * const file_mode[] = {"w+", "w", "r"};
+
+  if (fdfl & O_RDWR) {
+    return file_mode[0];
+  } else if (fdfl & O_WRONLY) {
+    return file_mode[1];
+  } else {
+    return file_mode[2];
+  }
+}
+}
+
+%fragment("is_obj_file", "header") {
+int
+is_obj_file(PyObject *obj) {
+  int fd, fdfl;
+  if (!PyLong_Check(obj) &&                                /* is not an integer */
+      PyObject_HasAttrString(obj, "fileno") &&             /* has fileno method */
+      (PyObject_CallMethod(obj, "flush", NULL) != NULL) && /* flush() succeeded */
+      ((fd = PyObject_AsFileDescriptor(obj)) != -1) &&     /* got file descriptor */
+      ((fdfl = fcntl(fd, F_GETFL)) != -1)                  /* got descriptor flags */
+    ) {
+    return 1;
+  }
+  else {
+    return 0;
+  }
+}
+}
+
+%fragment("obj_to_file","header", fragment="fdfl_to_str,is_obj_file") {
+FILE *
+obj_to_file(PyObject *obj) {
+  int fd, fdfl;
+  FILE *fp;
+  if (is_obj_file(obj)) {
+    fd = PyObject_AsFileDescriptor(obj);
+    fdfl = fcntl(fd, F_GETFL);
+    fp = fdopen(dup(fd), fdfl_to_str(fdfl)); /* the FILE* must be flushed
+                                                and closed after being used */
+#ifdef SWIG_FILE3_DEBUG
+    fprintf(stderr, "opening fd %d (fl %d \"%s\") as FILE %p\n",
+            fd, fdfl, fdfl_to_str(fdfl), (void *)fp);
+#endif
+    return fp;
+  }
+  return NULL;
+}
+}
+
+/* returns -1 if error occurred */
+/* caused magic SWIG Syntax errors when was commented out */
+#if 0
+%fragment("dispose_file", "header") {
+int
+dispose_file(FILE **fp) {
+#ifdef SWIG_FILE3_DEBUG
+  fprintf(stderr, "flushing FILE %p\n", (void *)fp);
+#endif
+  if (*fp == NULL) {
+    return 0;
+  }
+  if ((fflush(*fp) == 0) &&  /* flush file */
+      (fclose(*fp) == 0)) {  /* close file */
+    *fp = NULL;
+    return 0;
+  }
+  return -1;
+}
+}
+#endif
+
+%typemap(arginit, noblock = 1) FILE* {
+  $1 = NULL;
+}
+
+/*
+ * added due to ub_ctx_debugout since since it is overloaded:
+ * takes void* and FILE*. In reality only FILE* but the wrapper
+ * and the function is declared in such way.
+ */
+%typemap(typecheck, noblock = 1, fragment = "is_obj_file", precedence = SWIG_TYPECHECK_POINTER) FILE* {
+  $1 = is_obj_file($input);
+}
+
+%typemap(check, noblock = 1) FILE* {
+  if ($1 == NULL) {
+    /* The generated wrapper function raises TypeError on mismatching types. */
+    SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument "
+                        "$argnum"" of type '" "$type""'");
+  }
+}
+
+%typemap(in, noblock = 1, fragment = "obj_to_file") FILE* {
+  $1 = obj_to_file($input);
+}
+
+/*
+ * Commented out due the way how ub_ctx_debugout() uses the parameter.
+ * This typemap would cause the FILE* to be closed after return from
+ * the function. This caused Python interpreter to crash, since the
+ * function just stores the FILE* internally in ctx and use it for
+ * logging. So we'll leave the closing of the file on the OS.
+ */
+/*%typemap(freearg, noblock = 1, fragment = "dispose_file") FILE* {
+  if (dispose_file(&$1) == -1) {
+    SWIG_exception_fail(SWIG_IOError, "closing file in method '" "$symname" "', argument "
+                        "$argnum"" of type '" "$type""'");
+  }
+}*/
diff --git a/libunbound/worker.h b/libunbound/worker.h
new file mode 100644 (file)
index 0000000..a531501
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * libunbound/worker.h - prototypes for worker methods.
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file declares the methods any worker has to implement.
+ */
+
+#ifndef LIBUNBOUND_WORKER_H
+#define LIBUNBOUND_WORKER_H
+
+#include "sldns/sbuffer.h"
+#include "util/data/packed_rrset.h" /* for enum sec_status */
+struct comm_reply;
+struct comm_point;
+struct module_qstate;
+struct tube;
+
+/**
+ * Worker service routine to send serviced queries to authoritative servers.
+ * @param qname: query name. (host order)
+ * @param qnamelen: length in bytes of qname, including trailing 0.
+ * @param qtype: query type. (host order)
+ * @param qclass: query class. (host order)
+ * @param flags: host order flags word, with opcode and CD bit.
+ * @param dnssec: if set, EDNS record will have DO bit set.
+ * @param want_dnssec: signatures needed.
+ * @param nocaps: ignore capsforid(if in config), do not perturb qname.
+ * @param addr: where to.
+ * @param addrlen: length of addr.
+ * @param zone: delegation point name.
+ * @param zonelen: length of zone name wireformat dname.
+ * @param q: wich query state to reactivate upon return.
+ * @return: false on failure (memory or socket related). no query was
+ *      sent.
+ */
+struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
+        uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
+       int want_dnssec, int nocaps, struct sockaddr_storage* addr,
+       socklen_t addrlen, uint8_t* zone, size_t zonelen,
+       struct module_qstate* q);
+
+/** process incoming replies from the network */
+int libworker_handle_reply(struct comm_point* c, void* arg, int error,
+        struct comm_reply* reply_info);
+
+/** process incoming serviced query replies from the network */
+int libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
+        struct comm_reply* reply_info);
+
+/** handle control command coming into server */
+void libworker_handle_control_cmd(struct tube* tube, uint8_t* msg, size_t len,
+       int err, void* arg);
+
+/** mesh callback with fg results */
+void libworker_fg_done_cb(void* arg, int rcode, sldns_buffer* buf, 
+       enum sec_status s, char* why_bogus);
+
+/** mesh callback with bg results */
+void libworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf, 
+       enum sec_status s, char* why_bogus);
+
+/** mesh callback with event results */
+void libworker_event_done_cb(void* arg, int rcode, struct sldns_buffer* buf, 
+       enum sec_status s, char* why_bogus);
+
+/**
+ * Worker signal handler function. User argument is the worker itself.
+ * @param sig: signal number.
+ * @param arg: the worker (main worker) that handles signals.
+ */
+void worker_sighandler(int sig, void* arg);
+
+/**
+ * Worker service routine to send serviced queries to authoritative servers.
+ * @param qname: query name. (host order)
+ * @param qnamelen: length in bytes of qname, including trailing 0.
+ * @param qtype: query type. (host order)
+ * @param qclass: query class. (host order)
+ * @param flags: host order flags word, with opcode and CD bit.
+ * @param dnssec: if set, EDNS record will have DO bit set.
+ * @param want_dnssec: signatures needed.
+ * @param nocaps: ignore capsforid(if in config), do not perturb qname.
+ * @param addr: where to.
+ * @param addrlen: length of addr.
+ * @param zone: wireformat dname of the zone.
+ * @param zonelen: length of zone name.
+ * @param q: wich query state to reactivate upon return.
+ * @return: false on failure (memory or socket related). no query was
+ *      sent.
+ */
+struct outbound_entry* worker_send_query(uint8_t* qname, size_t qnamelen, 
+       uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, 
+       int want_dnssec, int nocaps, struct sockaddr_storage* addr,
+       socklen_t addrlen, uint8_t* zone, size_t zonelen,
+       struct module_qstate* q);
+
+/** 
+ * process control messages from the main thread. Frees the control 
+ * command message.
+ * @param tube: tube control message came on.
+ * @param msg: message contents.  Is freed.
+ * @param len: length of message.
+ * @param error: if error (NETEVENT_*) happened.
+ * @param arg: user argument
+ */
+void worker_handle_control_cmd(struct tube* tube, uint8_t* msg, size_t len,
+       int error, void* arg);
+
+/** handles callbacks from listening event interface */
+int worker_handle_request(struct comm_point* c, void* arg, int error,
+       struct comm_reply* repinfo);
+
+/** process incoming replies from the network */
+int worker_handle_reply(struct comm_point* c, void* arg, int error, 
+       struct comm_reply* reply_info);
+
+/** process incoming serviced query replies from the network */
+int worker_handle_service_reply(struct comm_point* c, void* arg, int error, 
+       struct comm_reply* reply_info);
+
+/** cleanup the cache to remove all rrset IDs from it, arg is worker */
+void worker_alloc_cleanup(void* arg);
+
+/** statistics timer callback handler */
+void worker_stat_timer_cb(void* arg);
+
+/** probe timer callback handler */
+void worker_probe_timer_cb(void* arg);
+
+/** start accept callback handler */
+void worker_start_accept(void* arg);
+
+/** stop accept callback handler */
+void worker_stop_accept(void* arg);
+
+/** handle remote control accept callbacks */
+int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*);
+
+/** handle remote control data callbacks */
+int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*);
+
+/** routine to printout option values over SSL */
+void  remote_get_opt_ssl(char* line, void* arg);
+
+#endif /* LIBUNBOUND_WORKER_H */
index 63ae69dc6fecaf83c52fba2ad334f4b1369fb1cd..bffda54187af4d101157c43c6c6d26dd735e51d3 100644 (file)
--- a/ltmain.sh
+++ b/ltmain.sh
@@ -70,7 +70,7 @@
 #         compiler:            $LTCC
 #         compiler flags:              $LTCFLAGS
 #         linker:              $LD (gnu? $with_gnu_ld)
-#         $progname:   (GNU libtool) 2.4.2
+#         $progname:   (GNU libtool) 2.4.2 Debian-2.4.2-1.11
 #         automake:    $automake_version
 #         autoconf:    $autoconf_version
 #
@@ -80,7 +80,7 @@
 
 PROGRAM=libtool
 PACKAGE=libtool
-VERSION=2.4.2
+VERSION="2.4.2 Debian-2.4.2-1.11"
 TIMESTAMP=""
 package_revision=1.3337
 
@@ -6124,7 +6124,10 @@ func_mode_link ()
        case $pass in
        dlopen) libs="$dlfiles" ;;
        dlpreopen) libs="$dlprefiles" ;;
-       link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+       link)
+         libs="$deplibs %DEPLIBS%"
+         test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
+         ;;
        esac
       fi
       if test "$linkmode,$pass" = "lib,dlpreopen"; then
@@ -6444,19 +6447,19 @@ func_mode_link ()
            # It is a libtool convenience library, so add in its objects.
            func_append convenience " $ladir/$objdir/$old_library"
            func_append old_convenience " $ladir/$objdir/$old_library"
+           tmp_libs=
+           for deplib in $dependency_libs; do
+             deplibs="$deplib $deplibs"
+             if $opt_preserve_dup_deps ; then
+               case "$tmp_libs " in
+               *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+               esac
+             fi
+             func_append tmp_libs " $deplib"
+           done
          elif test "$linkmode" != prog && test "$linkmode" != lib; then
            func_fatal_error "\`$lib' is not a convenience library"
          fi
-         tmp_libs=
-         for deplib in $dependency_libs; do
-           deplibs="$deplib $deplibs"
-           if $opt_preserve_dup_deps ; then
-             case "$tmp_libs " in
-             *" $deplib "*) func_append specialdeplibs " $deplib" ;;
-             esac
-           fi
-           func_append tmp_libs " $deplib"
-         done
          continue
        fi # $pass = conv
 
@@ -7349,6 +7352,9 @@ func_mode_link ()
            revision="$number_minor"
            lt_irix_increment=no
            ;;
+         *)
+           func_fatal_configuration "$modename: unknown library version type \`$version_type'"
+           ;;
          esac
          ;;
        no)
diff --git a/sldns/keyraw.c b/sldns/keyraw.c
new file mode 100644 (file)
index 0000000..59e8000
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * keyraw.c - raw key operations and conversions
+ *
+ * (c) NLnet Labs, 2004-2008
+ *
+ * See the file LICENSE for the license
+ */
+/**
+ * \file
+ * Implementation of raw DNSKEY functions (work on wire rdata).
+ */
+
+#include "config.h"
+#include "sldns/keyraw.h"
+#include "sldns/rrdef.h"
+
+#ifdef HAVE_SSL
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <openssl/md5.h>
+#ifdef HAVE_OPENSSL_ENGINE_H
+#  include <openssl/engine.h>
+#endif
+#endif /* HAVE_SSL */
+
+size_t
+sldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
+       const size_t len, int alg)
+{
+       /* for DSA keys */
+       uint8_t t;
+       
+       /* for RSA keys */
+       uint16_t exp;
+       uint16_t int16;
+       
+       switch ((sldns_algorithm)alg) {
+       case LDNS_DSA:
+       case LDNS_DSA_NSEC3:
+               if (len > 0) {
+                       t = keydata[0];
+                       return (64 + t*8)*8;
+               } else {
+                       return 0;
+               }
+               break;
+       case LDNS_RSAMD5:
+       case LDNS_RSASHA1:
+       case LDNS_RSASHA1_NSEC3:
+#ifdef USE_SHA2
+       case LDNS_RSASHA256:
+       case LDNS_RSASHA512:
+#endif
+               if (len > 0) {
+                       if (keydata[0] == 0) {
+                               /* big exponent */
+                               if (len > 3) {
+                                       memmove(&int16, keydata + 1, 2);
+                                       exp = ntohs(int16);
+                                       return (len - exp - 3)*8;
+                               } else {
+                                       return 0;
+                               }
+                       } else {
+                               exp = keydata[0];
+                               return (len-exp-1)*8;
+                       }
+               } else {
+                       return 0;
+               }
+               break;
+#ifdef USE_GOST
+       case LDNS_ECC_GOST:
+               return 512;
+#endif
+#ifdef USE_ECDSA
+        case LDNS_ECDSAP256SHA256:
+                return 256;
+        case LDNS_ECDSAP384SHA384:
+                return 384;
+#endif
+       default:
+               return 0;
+       }
+}
+
+uint16_t sldns_calc_keytag_raw(uint8_t* key, size_t keysize)
+{
+       if(keysize < 4) {
+               return 0;
+       }
+       /* look at the algorithm field, copied from 2535bis */
+       if (key[3] == LDNS_RSAMD5) {
+               uint16_t ac16 = 0;
+               if (keysize > 4) {
+                       memmove(&ac16, key + keysize - 3, 2);
+               }
+               ac16 = ntohs(ac16);
+               return (uint16_t) ac16;
+       } else {
+               size_t i;
+               uint32_t ac32 = 0;
+               for (i = 0; i < keysize; ++i) {
+                       ac32 += (i & 1) ? key[i] : key[i] << 8;
+               }
+               ac32 += (ac32 >> 16) & 0xFFFF;
+               return (uint16_t) (ac32 & 0xFFFF);
+       }
+}
+
+#ifdef HAVE_SSL
+#ifdef USE_GOST
+/** store GOST engine reference loaded into OpenSSL library */
+ENGINE* sldns_gost_engine = NULL;
+
+int
+sldns_key_EVP_load_gost_id(void)
+{
+       static int gost_id = 0;
+       const EVP_PKEY_ASN1_METHOD* meth;
+       ENGINE* e;
+
+       if(gost_id) return gost_id;
+
+       /* see if configuration loaded gost implementation from other engine*/
+       meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1);
+       if(meth) {
+               EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
+               return gost_id;
+       }
+
+       /* see if engine can be loaded already */
+       e = ENGINE_by_id("gost");
+       if(!e) {
+               /* load it ourself, in case statically linked */
+               ENGINE_load_builtin_engines();
+               ENGINE_load_dynamic();
+               e = ENGINE_by_id("gost");
+       }
+       if(!e) {
+               /* no gost engine in openssl */
+               return 0;
+       }
+       if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
+               ENGINE_finish(e);
+               ENGINE_free(e);
+               return 0;
+       }
+
+       meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1);
+       if(!meth) {
+               /* algo not found */
+               ENGINE_finish(e);
+               ENGINE_free(e);
+               return 0;
+       }
+        /* Note: do not ENGINE_finish and ENGINE_free the acquired engine
+         * on some platforms this frees up the meth and unloads gost stuff */
+        sldns_gost_engine = e;
+       
+       EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
+       return gost_id;
+} 
+
+void sldns_key_EVP_unload_gost(void)
+{
+        if(sldns_gost_engine) {
+                ENGINE_finish(sldns_gost_engine);
+                ENGINE_free(sldns_gost_engine);
+                sldns_gost_engine = NULL;
+        }
+}
+#endif /* USE_GOST */
+
+DSA *
+sldns_key_buf2dsa_raw(unsigned char* key, size_t len)
+{
+       uint8_t T;
+       uint16_t length;
+       uint16_t offset;
+       DSA *dsa;
+       BIGNUM *Q; BIGNUM *P;
+       BIGNUM *G; BIGNUM *Y;
+
+       if(len == 0)
+               return NULL;
+       T = (uint8_t)key[0];
+       length = (64 + T * 8);
+       offset = 1;
+
+       if (T > 8) {
+               return NULL;
+       }
+       if(len < (size_t)1 + SHA_DIGEST_LENGTH + 3*length)
+               return NULL;
+
+       Q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL);
+       offset += SHA_DIGEST_LENGTH;
+
+       P = BN_bin2bn(key+offset, (int)length, NULL);
+       offset += length;
+
+       G = BN_bin2bn(key+offset, (int)length, NULL);
+       offset += length;
+
+       Y = BN_bin2bn(key+offset, (int)length, NULL);
+       offset += length;
+
+       /* create the key and set its properties */
+       if(!Q || !P || !G || !Y || !(dsa = DSA_new())) {
+               BN_free(Q);
+               BN_free(P);
+               BN_free(G);
+               BN_free(Y);
+               return NULL;
+       }
+#ifndef S_SPLINT_S
+       dsa->p = P;
+       dsa->q = Q;
+       dsa->g = G;
+       dsa->pub_key = Y;
+#endif /* splint */
+
+       return dsa;
+}
+
+RSA *
+sldns_key_buf2rsa_raw(unsigned char* key, size_t len)
+{
+       uint16_t offset;
+       uint16_t exp;
+       uint16_t int16;
+       RSA *rsa;
+       BIGNUM *modulus;
+       BIGNUM *exponent;
+
+       if (len == 0)
+               return NULL;
+       if (key[0] == 0) {
+               if(len < 3)
+                       return NULL;
+               memmove(&int16, key+1, 2);
+               exp = ntohs(int16);
+               offset = 3;
+       } else {
+               exp = key[0];
+               offset = 1;
+       }
+
+       /* key length at least one */
+       if(len < (size_t)offset + exp + 1)
+               return NULL;
+
+       /* Exponent */
+       exponent = BN_new();
+       if(!exponent) return NULL;
+       (void) BN_bin2bn(key+offset, (int)exp, exponent);
+       offset += exp;
+
+       /* Modulus */
+       modulus = BN_new();
+       if(!modulus) {
+               BN_free(exponent);
+               return NULL;
+       }
+       /* length of the buffer must match the key length! */
+       (void) BN_bin2bn(key+offset, (int)(len - offset), modulus);
+
+       rsa = RSA_new();
+       if(!rsa) {
+               BN_free(exponent);
+               BN_free(modulus);
+               return NULL;
+       }
+#ifndef S_SPLINT_S
+       rsa->n = modulus;
+       rsa->e = exponent;
+#endif /* splint */
+
+       return rsa;
+}
+
+#ifdef USE_GOST
+EVP_PKEY*
+sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
+{
+       /* prefix header for X509 encoding */
+       uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, 
+               0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85, 
+               0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 
+               0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40};
+       unsigned char encoded[37+64];
+       const unsigned char* pp;
+       if(keylen != 64) {
+               /* key wrong size */
+               return NULL;
+       }
+
+       /* create evp_key */
+       memmove(encoded, asn, 37);
+       memmove(encoded+37, key, 64);
+       pp = (unsigned char*)&encoded[0];
+
+       return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded));
+}
+#endif /* USE_GOST */
+
+#ifdef USE_ECDSA
+EVP_PKEY*
+sldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo)
+{
+       unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */
+        const unsigned char* pp = buf;
+        EVP_PKEY *evp_key;
+        EC_KEY *ec;
+       /* check length, which uncompressed must be 2 bignums */
+        if(algo == LDNS_ECDSAP256SHA256) {
+               if(keylen != 2*256/8) return NULL;
+                ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+        } else if(algo == LDNS_ECDSAP384SHA384) {
+               if(keylen != 2*384/8) return NULL;
+                ec = EC_KEY_new_by_curve_name(NID_secp384r1);
+        } else    ec = NULL;
+        if(!ec) return NULL;
+       if(keylen+1 > sizeof(buf)) { /* sanity check */
+                EC_KEY_free(ec);
+               return NULL;
+       }
+       /* prepend the 0x02 (from docs) (or actually 0x04 from implementation
+        * of openssl) for uncompressed data */
+       buf[0] = POINT_CONVERSION_UNCOMPRESSED;
+       memmove(buf+1, key, keylen);
+        if(!o2i_ECPublicKey(&ec, &pp, (int)keylen+1)) {
+                EC_KEY_free(ec);
+                return NULL;
+        }
+        evp_key = EVP_PKEY_new();
+        if(!evp_key) {
+                EC_KEY_free(ec);
+                return NULL;
+        }
+        if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
+               EVP_PKEY_free(evp_key);
+               EC_KEY_free(ec);
+               return NULL;
+       }
+        return evp_key;
+}
+#endif /* USE_ECDSA */
+
+int
+sldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest,
+       const EVP_MD* md)
+{
+       EVP_MD_CTX* ctx;
+       ctx = EVP_MD_CTX_create();
+       if(!ctx)
+               return 0;
+       if(!EVP_DigestInit_ex(ctx, md, NULL) ||
+               !EVP_DigestUpdate(ctx, data, len) ||
+               !EVP_DigestFinal_ex(ctx, dest, NULL)) {
+               EVP_MD_CTX_destroy(ctx);
+               return 0;
+       }
+       EVP_MD_CTX_destroy(ctx);
+       return 1;
+}
+#endif /* HAVE_SSL */
diff --git a/sldns/keyraw.h b/sldns/keyraw.h
new file mode 100644 (file)
index 0000000..8abe235
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * keyraw.h -- raw key and signature access and conversion
+ *
+ * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ *
+ */
+
+/**
+ * \file
+ *
+ * raw key and signature access and conversion
+ *
+ * Since those functions heavily rely op cryptographic operations,
+ * this module is dependent on openssl.
+ * 
+ */
+#ifndef LDNS_KEYRAW_H
+#define LDNS_KEYRAW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+#  include <openssl/ssl.h>
+#  include <openssl/evp.h>
+#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+
+/**
+ * get the length of the keydata in bits
+ * \param[in] keydata the raw key data
+ * \param[in] len the length of the keydata
+ * \param[in] alg the cryptographic algorithm this is a key for
+ * \return the keysize in bits, or 0 on error
+ */
+size_t sldns_rr_dnskey_key_size_raw(const unsigned char *keydata,
+       const size_t len, int alg);
+
+/**
+ * Calculates keytag of DNSSEC key, operates on wireformat rdata.
+ * \param[in] key the key as uncompressed wireformat rdata.
+ * \param[in] keysize length of key data.
+ * \return the keytag
+ */
+uint16_t sldns_calc_keytag_raw(uint8_t* key, size_t keysize);
+
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+/** 
+ * Get the PKEY id for GOST, loads GOST into openssl as a side effect.
+ * Only available if GOST is compiled into the library and openssl.
+ * \return the gost id for EVP_CTX creation.
+ */
+int sldns_key_EVP_load_gost_id(void);
+
+/** Release the engine reference held for the GOST engine. */
+void sldns_key_EVP_unload_gost(void);
+
+/**
+ * Like sldns_key_buf2dsa, but uses raw buffer.
+ * \param[in] key the uncompressed wireformat of the key.
+ * \param[in] len length of key data
+ * \return a DSA * structure with the key material
+ */
+DSA *sldns_key_buf2dsa_raw(unsigned char* key, size_t len);
+
+/**
+ * Converts a holding buffer with key material to EVP PKEY in openssl.
+ * Only available if ldns was compiled with GOST.
+ * \param[in] key data to convert
+ * \param[in] keylen length of the key data
+ * \return the key or NULL on error.
+ */
+EVP_PKEY* sldns_gost2pkey_raw(unsigned char* key, size_t keylen);
+
+/**
+ * Converts a holding buffer with key material to EVP PKEY in openssl.
+ * Only available if ldns was compiled with ECDSA.
+ * \param[in] key data to convert
+ * \param[in] keylen length of the key data
+ * \param[in] algo precise algorithm to initialize ECC group values.
+ * \return the key or NULL on error.
+ */
+EVP_PKEY* sldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo);
+
+/**
+ * Like sldns_key_buf2rsa, but uses raw buffer.
+ * \param[in] key the uncompressed wireformat of the key.
+ * \param[in] len length of key data
+ * \return a RSA * structure with the key material
+ */
+RSA *sldns_key_buf2rsa_raw(unsigned char* key, size_t len);
+
+/**
+ * Utility function to calculate hash using generic EVP_MD pointer.
+ * \param[in] data the data to hash.
+ * \param[in] len  length of data.
+ * \param[out] dest the destination of the hash, must be large enough.
+ * \param[in] md the message digest to use.
+ * \return true if worked, false on failure.
+ */
+int sldns_digest_evp(unsigned char* data, unsigned int len, 
+       unsigned char* dest, const EVP_MD* md);
+
+#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_KEYRAW_H */
diff --git a/sldns/parse.c b/sldns/parse.c
new file mode 100644 (file)
index 0000000..35dee71
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * a generic (simple) parser. Use to parse rr's, private key
+ * information and /etc/resolv.conf files
+ *
+ * a Net::DNS like library for C
+ * LibDNS Team @ NLnet Labs
+ * (c) NLnet Labs, 2005-2006
+ * See the file LICENSE for the license
+ */
+#include "config.h"
+#include "sldns/parse.h"
+#include "sldns/parseutil.h"
+#include "sldns/sbuffer.h"
+
+#include <limits.h>
+#include <strings.h>
+
+sldns_lookup_table sldns_directive_types[] = {
+        { LDNS_DIR_TTL, "$TTL" },
+        { LDNS_DIR_ORIGIN, "$ORIGIN" },
+        { LDNS_DIR_INCLUDE, "$INCLUDE" },
+        { 0, NULL }
+};
+
+/* add max_limit here? */
+ssize_t
+sldns_fget_token(FILE *f, char *token, const char *delim, size_t limit)
+{
+       return sldns_fget_token_l(f, token, delim, limit, NULL);
+}
+
+ssize_t
+sldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr)
+{
+       int c, prev_c;
+       int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
+       int com, quoted;
+       char *t;
+       size_t i;
+       const char *d;
+       const char *del;
+
+       /* standard delimeters */
+       if (!delim) {
+               /* from isspace(3) */
+               del = LDNS_PARSE_NORMAL;
+       } else {
+               del = delim;
+       }
+
+       p = 0;
+       i = 0;
+       com = 0;
+       quoted = 0;
+       prev_c = 0;
+       t = token;
+       if (del[0] == '"') {
+               quoted = 1;
+       }
+       while ((c = getc(f)) != EOF) {
+               if (c == '\r') /* carriage return */
+                       c = ' ';
+               if (c == '(' && prev_c != '\\' && !quoted) {
+                       /* this only counts for non-comments */
+                       if (com == 0) {
+                               p++;
+                       }
+                       prev_c = c;
+                       continue;
+               }
+
+               if (c == ')' && prev_c != '\\' && !quoted) {
+                       /* this only counts for non-comments */
+                       if (com == 0) {
+                               p--;
+                       }
+                       prev_c = c;
+                       continue;
+               }
+
+               if (p < 0) {
+                       /* more ) then ( - close off the string */
+                       *t = '\0';
+                       return 0;
+               }
+
+               /* do something with comments ; */
+               if (c == ';' && quoted == 0) {
+                       if (prev_c != '\\') {
+                               com = 1;
+                       }
+               }
+               if (c == '\"' && com == 0 && prev_c != '\\') {
+                       quoted = 1 - quoted;
+               }
+
+               if (c == '\n' && com != 0) {
+                       /* comments */
+                       com = 0;
+                       *t = ' ';
+                       if (line_nr) {
+                               *line_nr = *line_nr + 1;
+                       }
+                       if (p == 0 && i > 0) {
+                               goto tokenread;
+                       } else {
+                               prev_c = c;
+                               continue;
+                       }
+               }
+
+               if (com == 1) {
+                       *t = ' ';
+                       prev_c = c;
+                       continue;
+               }
+
+               if (c == '\n' && p != 0 && t > token) {
+                       /* in parentheses */
+                       if (line_nr) {
+                               *line_nr = *line_nr + 1;
+                       }
+                       *t++ = ' ';
+                       prev_c = c;
+                       continue;
+               }
+
+               /* check if we hit the delim */
+               for (d = del; *d; d++) {
+                       if (c == *d && i > 0 && prev_c != '\\' && p == 0) {
+                               if (c == '\n' && line_nr) {
+                                       *line_nr = *line_nr + 1;
+                               }
+                               goto tokenread;
+                       }
+               }
+               if (c != '\0' && c != '\n') {
+                       i++;
+               }
+               if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) {
+                       *t = '\0';
+                       return -1;
+               }
+               if (c != '\0' && c != '\n') {
+                       *t++ = c;
+               }
+               if (c == '\\' && prev_c == '\\')
+                       prev_c = 0;
+               else    prev_c = c;
+       }
+       *t = '\0';
+       if (c == EOF) {
+               return (ssize_t)i;
+       }
+
+       if (i == 0) {
+               /* nothing read */
+               return -1;
+       }
+       if (p != 0) {
+               return -1;
+       }
+       return (ssize_t)i;
+
+tokenread:
+       if(*del == '"')
+               /* do not skip over quotes after the string, they are part
+                * of the next string.  But skip over whitespace (if needed)*/
+               sldns_fskipcs_l(f, del+1, line_nr);
+       else    sldns_fskipcs_l(f, del, line_nr);
+       *t = '\0';
+       if (p != 0) {
+               return -1;
+       }
+
+       return (ssize_t)i;
+}
+
+ssize_t
+sldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data,
+               const char *d_del, size_t data_limit)
+{
+       return sldns_fget_keyword_data_l(f, keyword, k_del, data, d_del,
+                      data_limit, NULL);
+}
+
+ssize_t
+sldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del, char *data,
+               const char *d_del, size_t data_limit, int *line_nr)
+{
+       /* we assume: keyword|sep|data */
+       char *fkeyword;
+       ssize_t i;
+
+       if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN)
+               return -1;
+       fkeyword = (char*)malloc(LDNS_MAX_KEYWORDLEN);
+       if(!fkeyword)
+               return -1;
+
+       i = sldns_fget_token(f, fkeyword, k_del, LDNS_MAX_KEYWORDLEN);
+       if(i==0 || i==-1) {
+               free(fkeyword);
+               return -1;
+       }
+
+       /* case??? i instead of strlen? */
+       if (strncmp(fkeyword, keyword, LDNS_MAX_KEYWORDLEN - 1) == 0) {
+               /* whee! */
+               /* printf("%s\n%s\n", "Matching keyword", fkeyword); */
+               i = sldns_fget_token_l(f, data, d_del, data_limit, line_nr);
+               free(fkeyword);
+               return i;
+       } else {
+               /*printf("no match for %s (read: %s)\n", keyword, fkeyword);*/
+               free(fkeyword);
+               return -1;
+       }
+}
+
+int
+sldns_bgetc(sldns_buffer *buffer)
+{
+       if (!sldns_buffer_available_at(buffer, buffer->_position, sizeof(uint8_t))) {
+               sldns_buffer_set_position(buffer, sldns_buffer_limit(buffer));
+               /* sldns_buffer_rewind(buffer);*/
+               return EOF;
+       }
+       return (int)sldns_buffer_read_u8(buffer);
+}
+
+ssize_t
+sldns_bget_token(sldns_buffer *b, char *token, const char *delim, size_t limit)
+{
+       return sldns_bget_token_par(b, token, delim, limit, NULL, NULL);
+}
+
+ssize_t
+sldns_bget_token_par(sldns_buffer *b, char *token, const char *delim,
+       size_t limit, int* par, const char* skipw)
+{
+       int c, lc;
+       int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
+       int com, quoted;
+       char *t;
+       size_t i;
+       const char *d;
+       const char *del;
+
+       /* standard delimiters */
+       if (!delim) {
+               /* from isspace(3) */
+               del = LDNS_PARSE_NORMAL;
+       } else {
+               del = delim;
+       }
+
+       p = (par?*par:0);
+       i = 0;
+       com = 0;
+       quoted = 0;
+       t = token;
+       lc = 0;
+       if (del[0] == '"') {
+               quoted = 1;
+       }
+
+       while ((c = sldns_bgetc(b)) != EOF) {
+               if (c == '\r') /* carriage return */
+                       c = ' ';
+               if (c == '(' && lc != '\\' && !quoted) {
+                       /* this only counts for non-comments */
+                       if (com == 0) {
+                               if(par) (*par)++;
+                               p++;
+                       }
+                       lc = c;
+                       continue;
+               }
+
+               if (c == ')' && lc != '\\' && !quoted) {
+                       /* this only counts for non-comments */
+                       if (com == 0) {
+                               if(par) (*par)--;
+                               p--;
+                       }
+                       lc = c;
+                       continue;
+               }
+
+               if (p < 0) {
+                       /* more ) then ( */
+                       *t = '\0';
+                       return 0;
+               }
+
+               /* do something with comments ; */
+               if (c == ';' && quoted == 0) {
+                       if (lc != '\\') {
+                               com = 1;
+                       }
+               }
+               if (c == '"' && com == 0 && lc != '\\') {
+                       quoted = 1 - quoted;
+               }
+
+               if (c == '\n' && com != 0) {
+                       /* comments */
+                       com = 0;
+                       *t = ' ';
+                       lc = c;
+                       continue;
+               }
+
+               if (com == 1) {
+                       *t = ' ';
+                       lc = c;
+                       continue;
+               }
+
+               if (c == '\n' && p != 0) {
+                       /* in parentheses */
+                       /* do not write ' ' if we want to skip spaces */
+                       if(!(skipw && (strchr(skipw, c)||strchr(skipw, ' '))))
+                               *t++ = ' ';
+                       lc = c;
+                       continue;
+               }
+
+               /* check to skip whitespace at start, but also after ( */
+               if(skipw && i==0 && !com && !quoted && lc != '\\') {
+                       if(strchr(skipw, c)) {
+                               lc = c;
+                               continue;
+                       }
+               }
+
+               /* check if we hit the delim */
+               for (d = del; *d; d++) {
+                       /* we can only exit if no parens or user tracks them */
+                        if (c == *d && lc != '\\' && (p == 0 || par)) {
+                               goto tokenread;
+                        }
+               }
+
+               i++;
+               if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) {
+                       *t = '\0';
+                       return -1;
+               }
+               *t++ = c;
+
+               if (c == '\\' && lc == '\\') {
+                       lc = 0;
+               } else {
+                       lc = c;
+               }
+       }
+       *t = '\0';
+       if (i == 0) {
+               /* nothing read */
+               return -1;
+       }
+       if (!par && p != 0) {
+               return -1;
+       }
+       return (ssize_t)i;
+
+tokenread:
+       if(*del == '"')
+               /* do not skip over quotes after the string, they are part
+                * of the next string.  But skip over whitespace (if needed)*/
+               sldns_bskipcs(b, del+1);
+       else    sldns_bskipcs(b, del);
+       *t = '\0';
+
+       if (!par && p != 0) {
+               return -1;
+       }
+       return (ssize_t)i;
+}
+
+
+void
+sldns_bskipcs(sldns_buffer *buffer, const char *s)
+{
+        int found;
+        char c;
+        const char *d;
+
+        while(sldns_buffer_available_at(buffer, buffer->_position, sizeof(char))) {
+                c = (char) sldns_buffer_read_u8_at(buffer, buffer->_position);
+                found = 0;
+                for (d = s; *d; d++) {
+                        if (*d == c) {
+                                found = 1;
+                        }
+                }
+                if (found && buffer->_limit > buffer->_position) {
+                        buffer->_position += sizeof(char);
+                } else {
+                        return;
+                }
+        }
+}
+
+void
+sldns_fskipcs(FILE *fp, const char *s)
+{
+       sldns_fskipcs_l(fp, s, NULL);
+}
+
+void
+sldns_fskipcs_l(FILE *fp, const char *s, int *line_nr)
+{
+        int found;
+        int c;
+        const char *d;
+
+       while ((c = fgetc(fp)) != EOF) {
+               if (line_nr && c == '\n') {
+                       *line_nr = *line_nr + 1;
+               }
+                found = 0;
+                for (d = s; *d; d++) {
+                        if (*d == c) {
+                                found = 1;
+                        }
+                }
+               if (!found) {
+                       /* with getc, we've read too far */
+                       ungetc(c, fp);
+                       return;
+               }
+       }
+}
+
+ssize_t
+sldns_bget_keyword_data(sldns_buffer *b, const char *keyword, const char *k_del, char
+*data, const char *d_del, size_t data_limit)
+{
+       /* we assume: keyword|sep|data */
+       char *fkeyword;
+       ssize_t i;
+
+       if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN)
+               return -1;
+       fkeyword = (char*)malloc(LDNS_MAX_KEYWORDLEN);
+       if(!fkeyword)
+               return -1; /* out of memory */
+
+       i = sldns_bget_token(b, fkeyword, k_del, data_limit);
+       if(i==0 || i==-1) {
+               free(fkeyword);
+               return -1; /* nothing read */
+       }
+
+       /* case??? */
+       if (strncmp(fkeyword, keyword, strlen(keyword)) == 0) {
+               free(fkeyword);
+               /* whee, the match! */
+               /* retrieve it's data */
+               i = sldns_bget_token(b, data, d_del, 0);
+               return i;
+       } else {
+               free(fkeyword);
+               return -1;
+       }
+}
+
diff --git a/sldns/parse.h b/sldns/parse.h
new file mode 100644 (file)
index 0000000..7b7456d
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * parse.h 
+ *
+ * a Net::DNS like library for C
+ * LibDNS Team @ NLnet Labs
+ * (c) NLnet Labs, 2005-2006
+ * See the file LICENSE for the license
+ */
+
+#ifndef LDNS_PARSE_H
+#define LDNS_PARSE_H
+
+struct sldns_buffer;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDNS_PARSE_SKIP_SPACE          "\f\n\r\v"
+#define LDNS_PARSE_NORMAL              " \f\n\r\t\v"
+#define LDNS_PARSE_NO_NL               " \t"
+#define LDNS_MAX_LINELEN               10230
+#define LDNS_MAX_KEYWORDLEN            32
+
+
+/**
+ * \file
+ *
+ * Contains some low-level parsing functions, mostly used in the _frm_str
+ * family of functions.
+ */
+/**
+ * different type of directives in zone files
+ * We now deal with $TTL, $ORIGIN and $INCLUDE.
+ * The latter is not implemented in ldns (yet)
+ */
+enum sldns_enum_directive
+{
+       LDNS_DIR_TTL,
+       LDNS_DIR_ORIGIN,
+       LDNS_DIR_INCLUDE
+};
+typedef enum sldns_enum_directive sldns_directive;
+
+/** 
+ * returns a token/char from the stream F.
+ * This function deals with ( and ) in the stream,
+ * and ignores them when encountered
+ * \param[in] *f the file to read from
+ * \param[out] *token the read token is put here
+ * \param[in] *delim chars at which the parsing should stop
+ * \param[in] *limit how much to read. If 0 the builtin maximum is used
+ * \return 0 on error of EOF of the stream F.  Otherwise return the length of what is read
+ */
+ssize_t sldns_fget_token(FILE *f, char *token, const char *delim, size_t limit);
+
+/** 
+ * returns a token/char from the stream F.
+ * This function deals with ( and ) in the stream,
+ * and ignores when it finds them.
+ * \param[in] *f the file to read from
+ * \param[out] *token the token is put here
+ * \param[in] *delim chars at which the parsing should stop
+ * \param[in] *limit how much to read. If 0 use builtin maximum
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \return 0 on error of EOF of F otherwise return the length of what is read
+ */
+ssize_t sldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr);
+
+/**
+ * returns a token/char from the buffer b.
+ * This function deals with ( and ) in the buffer,
+ * and ignores when it finds them.
+ * \param[in] *b the buffer to read from
+ * \param[out] *token the token is put here
+ * \param[in] *delim chars at which the parsing should stop
+ * \param[in] *limit how much to read. If 0 the builtin maximum is used
+ * \param[in] *par if you pass nonNULL, set to 0 on first call, the parenthesis
+ * state is stored in it, for use on next call.  User must check it is back
+ * to zero after last bget in string (for parse error).  If you pass NULL,
+ * the entire parenthesized string is read in.
+ * \param[in] skipw string with whitespace to skip before the start of the
+ * token, like " ", or " \t", or NULL for none.  
+ * \returns 0 on error of EOF of b. Otherwise return the length of what is read
+ */
+ssize_t sldns_bget_token_par(struct sldns_buffer *b, char *token, const char *delim, size_t limit, int* par, const char* skipw);
+
+/**
+ * returns a token/char from the buffer b.
+ * This function deals with ( and ) in the buffer,
+ * and ignores when it finds them.
+ * \param[in] *b the buffer to read from
+ * \param[out] *token the token is put here
+ * \param[in] *delim chars at which the parsing should stop
+ * \param[in] *limit how much to read. If 0 the builtin maximum is used
+ * \returns 0 on error of EOF of b. Otherwise return the length of what is read
+ */
+ssize_t sldns_bget_token(struct sldns_buffer *b, char *token, const char *delim, size_t limit);
+
+/*
+ * searches for keyword and delim in a file. Gives everything back
+ * after the keyword + k_del until we hit d_del
+ * \param[in] f file pointer to read from
+ * \param[in] keyword keyword to look for
+ * \param[in] k_del keyword delimeter 
+ * \param[out] data the data found 
+ * \param[in] d_del the data delimeter
+ * \param[in] data_limit maximum size the the data buffer
+ * \return the number of character read
+ */
+ssize_t sldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit);
+
+/*
+ * searches for keyword and delim. Gives everything back
+ * after the keyword + k_del until we hit d_del
+ * \param[in] f file pointer to read from
+ * \param[in] keyword keyword to look for
+ * \param[in] k_del keyword delimeter 
+ * \param[out] data the data found 
+ * \param[in] d_del the data delimeter
+ * \param[in] data_limit maximum size the the data buffer
+ * \param[in] line_nr pointer to an integer containing the current line number (for
+debugging purposes)
+ * \return the number of character read
+ */
+ssize_t sldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit, int *line_nr);
+
+/*
+ * searches for keyword and delim in a buffer. Gives everything back
+ * after the keyword + k_del until we hit d_del
+ * \param[in] b buffer pointer to read from
+ * \param[in] keyword keyword to look for
+ * \param[in] k_del keyword delimeter 
+ * \param[out] data the data found 
+ * \param[in] d_del the data delimeter
+ * \param[in] data_limit maximum size the the data buffer
+ * \return the number of character read
+ */
+ssize_t sldns_bget_keyword_data(struct sldns_buffer *b, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit);
+
+/**
+ * returns the next character from a buffer. Advances the position pointer with 1.
+ * When end of buffer is reached returns EOF. This is the buffer's equivalent
+ * for getc().
+ * \param[in] *buffer buffer to read from
+ * \return EOF on failure otherwise return the character
+ */
+int sldns_bgetc(struct sldns_buffer *buffer);
+
+/**
+ * skips all of the characters in the given string in the buffer, moving
+ * the position to the first character that is not in *s.
+ * \param[in] *buffer buffer to use
+ * \param[in] *s characters to skip
+ * \return void
+ */
+void sldns_bskipcs(struct sldns_buffer *buffer, const char *s);
+
+/**
+ * skips all of the characters in the given string in the fp, moving
+ * the position to the first character that is not in *s.
+ * \param[in] *fp file to use
+ * \param[in] *s characters to skip
+ * \return void
+ */
+void sldns_fskipcs(FILE *fp, const char *s);
+
+
+/**
+ * skips all of the characters in the given string in the fp, moving
+ * the position to the first character that is not in *s.
+ * \param[in] *fp file to use
+ * \param[in] *s characters to skip
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \return void
+ */
+void sldns_fskipcs_l(FILE *fp, const char *s, int *line_nr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_PARSE_H */
diff --git a/sldns/parseutil.c b/sldns/parseutil.c
new file mode 100644 (file)
index 0000000..2a2ebbb
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ * parseutil.c - parse utilities for string and wire conversion
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+/**
+ * \file
+ *
+ * Utility functions for parsing, base32(DNS variant) and base64 encoding
+ * and decoding, Hex, Time units, Escape codes.
+ */
+
+#include "config.h"
+#include "sldns/parseutil.h"
+#include <sys/time.h>
+#include <time.h>
+#include <ctype.h>
+
+sldns_lookup_table *
+sldns_lookup_by_name(sldns_lookup_table *table, const char *name)
+{
+        while (table->name != NULL) {
+                if (strcasecmp(name, table->name) == 0)
+                        return table;
+                table++;
+        }
+        return NULL;
+}
+
+sldns_lookup_table *
+sldns_lookup_by_id(sldns_lookup_table *table, int id)
+{
+        while (table->name != NULL) {
+                if (table->id == id)
+                        return table;
+                table++;
+        }
+        return NULL;
+}
+
+/* Number of days per month (except for February in leap years). */
+static const int mdays[] = {
+       31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define LDNS_MOD(x,y) (((x) % (y) < 0) ? ((x) % (y) + (y)) : ((x) % (y)))
+#define LDNS_DIV(x,y) (((x) % (y) < 0) ? ((x) / (y) -  1 ) : ((x) / (y)))
+
+static int
+is_leap_year(int year)
+{
+       return LDNS_MOD(year,   4) == 0 && (LDNS_MOD(year, 100) != 0 
+           || LDNS_MOD(year, 400) == 0);
+}
+
+static int
+leap_days(int y1, int y2)
+{
+       --y1;
+       --y2;
+       return (LDNS_DIV(y2,   4) - LDNS_DIV(y1,   4)) - 
+              (LDNS_DIV(y2, 100) - LDNS_DIV(y1, 100)) +
+              (LDNS_DIV(y2, 400) - LDNS_DIV(y1, 400));
+}
+
+/*
+ * Code adapted from Python 2.4.1 sources (Lib/calendar.py).
+ */
+time_t
+sldns_mktime_from_utc(const struct tm *tm)
+{
+       int year = 1900 + tm->tm_year;
+       time_t days = 365 * ((time_t) year - 1970) + leap_days(1970, year);
+       time_t hours;
+       time_t minutes;
+       time_t seconds;
+       int i;
+
+       for (i = 0; i < tm->tm_mon; ++i) {
+               days += mdays[i];
+       }
+       if (tm->tm_mon > 1 && is_leap_year(year)) {
+               ++days;
+       }
+       days += tm->tm_mday - 1;
+
+       hours = days * 24 + tm->tm_hour;
+       minutes = hours * 60 + tm->tm_min;
+       seconds = minutes * 60 + tm->tm_sec;
+
+       return seconds;
+}
+
+#if SIZEOF_TIME_T <= 4
+
+static void
+sldns_year_and_yday_from_days_since_epoch(int64_t days, struct tm *result)
+{
+       int year = 1970;
+       int new_year;
+
+       while (days < 0 || days >= (int64_t) (is_leap_year(year) ? 366 : 365)) {
+               new_year = year + (int) LDNS_DIV(days, 365);
+               days -= (new_year - year) * 365;
+               days -= leap_days(year, new_year);
+               year  = new_year;
+       }
+       result->tm_year = year;
+       result->tm_yday = (int) days;
+}
+
+/* Number of days per month in a leap year. */
+static const int leap_year_mdays[] = {
+       31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static void
+sldns_mon_and_mday_from_year_and_yday(struct tm *result)
+{
+       int idays = result->tm_yday;
+       const int *mon_lengths = is_leap_year(result->tm_year) ? 
+                                       leap_year_mdays : mdays;
+
+       result->tm_mon = 0;
+       while  (idays >= mon_lengths[result->tm_mon]) {
+               idays -= mon_lengths[result->tm_mon++];
+       }
+       result->tm_mday = idays + 1;
+}
+
+static void
+sldns_wday_from_year_and_yday(struct tm *result)
+{
+       result->tm_wday = 4 /* 1-1-1970 was a thursday */
+                       + LDNS_MOD((result->tm_year - 1970), 7) * LDNS_MOD(365, 7)
+                       + leap_days(1970, result->tm_year)
+                       + result->tm_yday;
+       result->tm_wday = LDNS_MOD(result->tm_wday, 7);
+       if (result->tm_wday < 0) {
+               result->tm_wday += 7;
+       }
+}
+
+static struct tm *
+sldns_gmtime64_r(int64_t clock, struct tm *result)
+{
+       result->tm_isdst = 0;
+       result->tm_sec   = (int) LDNS_MOD(clock, 60);
+       clock            =       LDNS_DIV(clock, 60);
+       result->tm_min   = (int) LDNS_MOD(clock, 60);
+       clock            =       LDNS_DIV(clock, 60);
+       result->tm_hour  = (int) LDNS_MOD(clock, 24);
+       clock            =       LDNS_DIV(clock, 24);
+
+       sldns_year_and_yday_from_days_since_epoch(clock, result);
+       sldns_mon_and_mday_from_year_and_yday(result);
+       sldns_wday_from_year_and_yday(result);
+       result->tm_year -= 1900;
+
+       return result;
+}
+
+#endif /* SIZEOF_TIME_T <= 4 */
+
+static int64_t
+sldns_serial_arithmitics_time(int32_t time, time_t now)
+{
+       int32_t offset = time - (int32_t) now;
+       return (int64_t) now + offset;
+}
+
+struct tm *
+sldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result)
+{
+#if SIZEOF_TIME_T <= 4
+       int64_t secs_since_epoch = sldns_serial_arithmitics_time(time, now);
+       return  sldns_gmtime64_r(secs_since_epoch, result);
+#else
+       time_t  secs_since_epoch = sldns_serial_arithmitics_time(time, now);
+       return  gmtime_r(&secs_since_epoch, result);
+#endif
+}
+
+int
+sldns_hexdigit_to_int(char ch)
+{
+       switch (ch) {
+       case '0': return 0;
+       case '1': return 1;
+       case '2': return 2;
+       case '3': return 3;
+       case '4': return 4;
+       case '5': return 5;
+       case '6': return 6;
+       case '7': return 7;
+       case '8': return 8;
+       case '9': return 9;
+       case 'a': case 'A': return 10;
+       case 'b': case 'B': return 11;
+       case 'c': case 'C': return 12;
+       case 'd': case 'D': return 13;
+       case 'e': case 'E': return 14;
+       case 'f': case 'F': return 15;
+       default:
+               return -1;
+       }
+}
+
+uint32_t
+sldns_str2period(const char *nptr, const char **endptr)
+{
+       int sign = 0;
+       uint32_t i = 0;
+       uint32_t seconds = 0;
+
+       for(*endptr = nptr; **endptr; (*endptr)++) {
+               switch (**endptr) {
+                       case ' ':
+                       case '\t':
+                               break;
+                       case '-':
+                               if(sign == 0) {
+                                       sign = -1;
+                               } else {
+                                       return seconds;
+                               }
+                               break;
+                       case '+':
+                               if(sign == 0) {
+                                       sign = 1;
+                               } else {
+                                       return seconds;
+                               }
+                               break;
+                       case 's':
+                       case 'S':
+                               seconds += i;
+                               i = 0;
+                               break;
+                       case 'm':
+                       case 'M':
+                               seconds += i * 60;
+                               i = 0;
+                               break;
+                       case 'h':
+                       case 'H':
+                               seconds += i * 60 * 60;
+                               i = 0;
+                               break;
+                       case 'd':
+                       case 'D':
+                               seconds += i * 60 * 60 * 24;
+                               i = 0;
+                               break;
+                       case 'w':
+                       case 'W':
+                               seconds += i * 60 * 60 * 24 * 7;
+                               i = 0;
+                               break;
+                       case '0':
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                       case '9':
+                               i *= 10;
+                               i += (**endptr - '0');
+                               break;
+                       default:
+                               seconds += i;
+                               /* disregard signedness */
+                               return seconds;
+               }
+       }
+       seconds += i;
+       /* disregard signedness */
+       return seconds;
+}
+
+int
+sldns_parse_escape(uint8_t *ch_p, const char** str_p)
+{
+       uint16_t val;
+
+       if ((*str_p)[0] && isdigit((unsigned char)(*str_p)[0]) &&
+           (*str_p)[1] && isdigit((unsigned char)(*str_p)[1]) &&
+           (*str_p)[2] && isdigit((unsigned char)(*str_p)[2])) {
+
+               val = (uint16_t)(((*str_p)[0] - '0') * 100 +
+                                ((*str_p)[1] - '0') *  10 +
+                                ((*str_p)[2] - '0'));
+
+               if (val > 255) {
+                       goto error;
+               }
+               *ch_p = (uint8_t)val;
+               *str_p += 3;
+               return 1;
+
+       } else if ((*str_p)[0] && !isdigit((unsigned char)(*str_p)[0])) {
+
+               *ch_p = (uint8_t)*(*str_p)++;
+               return 1;
+       }
+error:
+       *str_p = NULL;
+       return 0; /* LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE */
+}
+
+/** parse one character, with escape codes */
+int
+sldns_parse_char(uint8_t *ch_p, const char** str_p)
+{
+       switch (**str_p) {
+
+       case '\0':      return 0;
+
+       case '\\':      *str_p += 1;
+                       return sldns_parse_escape(ch_p, str_p);
+
+       default:        *ch_p = (uint8_t)*(*str_p)++;
+                       return 1;
+       }
+}
+
+size_t sldns_b32_ntop_calculate_size(size_t src_data_length)
+{
+       return src_data_length == 0 ? 0 : ((src_data_length - 1) / 5 + 1) * 8;
+}
+
+size_t sldns_b32_ntop_calculate_size_no_padding(size_t src_data_length)
+{
+       return ((src_data_length + 3) * 8 / 5) - 4;
+}
+
+static int
+sldns_b32_ntop_base(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz,
+       int extended_hex, int add_padding)
+{
+       size_t ret_sz;
+       const char* b32 = extended_hex ?  "0123456789abcdefghijklmnopqrstuv"
+                                       : "abcdefghijklmnopqrstuvwxyz234567";
+
+       size_t c = 0; /* c is used to carry partial base32 character over 
+                      * byte boundaries for sizes with a remainder.
+                      * (i.e. src_sz % 5 != 0)
+                      */
+
+       ret_sz = add_padding ? sldns_b32_ntop_calculate_size(src_sz)
+                            : sldns_b32_ntop_calculate_size_no_padding(src_sz);
+       
+       /* Do we have enough space? */
+       if (dst_sz < ret_sz + 1)
+               return -1;
+
+       /* We know the size; terminate the string */
+       dst[ret_sz] = '\0';
+
+       /* First process all chunks of five */
+       while (src_sz >= 5) {
+               /* 00000... ........ ........ ........ ........ */
+               dst[0] = b32[(src[0]       ) >> 3];
+
+               /* .....111 11...... ........ ........ ........ */
+               dst[1] = b32[(src[0] & 0x07) << 2 | src[1] >> 6];
+
+               /* ........ ..22222. ........ ........ ........ */
+               dst[2] = b32[(src[1] & 0x3e) >> 1];
+
+               /* ........ .......3 3333.... ........ ........ */
+               dst[3] = b32[(src[1] & 0x01) << 4 | src[2] >> 4];
+
+               /* ........ ........ ....4444 4....... ........ */
+               dst[4] = b32[(src[2] & 0x0f) << 1 | src[3] >> 7];
+
+               /* ........ ........ ........ .55555.. ........ */
+               dst[5] = b32[(src[3] & 0x7c) >> 2];
+
+               /* ........ ........ ........ ......66 666..... */
+               dst[6] = b32[(src[3] & 0x03) << 3 | src[4] >> 5];
+
+               /* ........ ........ ........ ........ ...77777 */
+               dst[7] = b32[(src[4] & 0x1f)     ];
+
+               src_sz -= 5;
+               src    += 5;
+               dst    += 8;
+       }
+       /* Process what remains */
+       switch (src_sz) {
+       case 4: /* ........ ........ ........ ......66 666..... */
+               dst[6] = b32[(src[3] & 0x03) << 3];
+
+               /* ........ ........ ........ .55555.. ........ */
+               dst[5] = b32[(src[3] & 0x7c) >> 2];
+
+               /* ........ ........ ....4444 4....... ........ */
+                        c =  src[3]         >> 7 ;
+       case 3: dst[4] = b32[(src[2] & 0x0f) << 1 | c];
+
+               /* ........ .......3 3333.... ........ ........ */
+                        c =  src[2]         >> 4 ;
+       case 2: dst[3] = b32[(src[1] & 0x01) << 4 | c];
+
+               /* ........ ..22222. ........ ........ ........ */
+               dst[2] = b32[(src[1] & 0x3e) >> 1];
+
+               /* .....111 11...... ........ ........ ........ */
+                        c =  src[1]         >> 6 ;
+       case 1: dst[1] = b32[(src[0] & 0x07) << 2 | c];
+
+               /* 00000... ........ ........ ........ ........ */
+               dst[0] = b32[ src[0]         >> 3];
+       }
+       /* Add padding */
+       if (add_padding) {
+               switch (src_sz) {
+                       case 1: dst[2] = '=';
+                               dst[3] = '=';
+                       case 2: dst[4] = '=';
+                       case 3: dst[5] = '=';
+                               dst[6] = '=';
+                       case 4: dst[7] = '=';
+               }
+       }
+       return (int)ret_sz;
+}
+
+int 
+sldns_b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz)
+{
+       return sldns_b32_ntop_base(src, src_sz, dst, dst_sz, 0, 1);
+}
+
+int 
+sldns_b32_ntop_extended_hex(const uint8_t* src, size_t src_sz,
+               char* dst, size_t dst_sz)
+{
+       return sldns_b32_ntop_base(src, src_sz, dst, dst_sz, 1, 1);
+}
+
+size_t sldns_b32_pton_calculate_size(size_t src_text_length)
+{
+       return src_text_length * 5 / 8;
+}
+
+static int
+sldns_b32_pton_base(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz,
+       int extended_hex, int check_padding)
+{
+       size_t i = 0;
+       char ch = '\0';
+       uint8_t buf[8];
+       uint8_t* start = dst;
+
+       while (src_sz) {
+               /* Collect 8 characters in buf (if possible) */
+               for (i = 0; i < 8; i++) {
+
+                       do {
+                               ch = *src++;
+                               --src_sz;
+
+                       } while (isspace((unsigned char)ch) && src_sz > 0);
+
+                       if (ch == '=' || ch == '\0')
+                               break;
+
+                       else if (extended_hex)
+
+                               if (ch >= '0' && ch <= '9')
+                                       buf[i] = (uint8_t)ch - '0';
+                               else if (ch >= 'a' && ch <= 'v')
+                                       buf[i] = (uint8_t)ch - 'a' + 10;
+                               else if (ch >= 'A' && ch <= 'V')
+                                       buf[i] = (uint8_t)ch - 'A' + 10;
+                               else
+                                       return -1;
+
+                       else if (ch >= 'a' && ch <= 'z')
+                               buf[i] = (uint8_t)ch - 'a';
+                       else if (ch >= 'A' && ch <= 'Z')
+                               buf[i] = (uint8_t)ch - 'A';
+                       else if (ch >= '2' && ch <= '7')
+                               buf[i] = (uint8_t)ch - '2' + 26;
+                       else
+                               return -1;
+               }
+               /* Less that 8 characters. We're done. */
+               if (i < 8)
+                       break;
+
+               /* Enough space available at the destination? */
+               if (dst_sz < 5)
+                       return -1;
+
+               /* 00000... ........ ........ ........ ........ */
+               /* .....111 11...... ........ ........ ........ */
+               dst[0] = buf[0] << 3 | buf[1] >> 2;
+
+               /* .....111 11...... ........ ........ ........ */
+               /* ........ ..22222. ........ ........ ........ */
+               /* ........ .......3 3333.... ........ ........ */
+               dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4;
+
+               /* ........ .......3 3333.... ........ ........ */
+               /* ........ ........ ....4444 4....... ........ */
+               dst[2] = buf[3] << 4 | buf[4] >> 1;
+
+               /* ........ ........ ....4444 4....... ........ */
+               /* ........ ........ ........ .55555.. ........ */
+               /* ........ ........ ........ ......66 666..... */
+               dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3;
+
+               /* ........ ........ ........ ......66 666..... */
+               /* ........ ........ ........ ........ ...77777 */
+               dst[4] = buf[6] << 5 | buf[7];
+
+               dst += 5;
+               dst_sz -= 5;
+       }
+       /* Not ending on a eight byte boundary? */
+       if (i > 0 && i < 8) {
+
+               /* Enough space available at the destination? */
+               if (dst_sz < (i + 1) / 2)
+                       return -1;
+
+               switch (i) {
+               case 7: /* ........ ........ ........ ......66 666..... */
+                       /* ........ ........ ........ .55555.. ........ */
+                       /* ........ ........ ....4444 4....... ........ */
+                       dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3;
+
+               case 5: /* ........ ........ ....4444 4....... ........ */
+                       /* ........ .......3 3333.... ........ ........ */
+                       dst[2] = buf[3] << 4 | buf[4] >> 1;
+
+               case 4: /* ........ .......3 3333.... ........ ........ */
+                       /* ........ ..22222. ........ ........ ........ */
+                       /* .....111 11...... ........ ........ ........ */
+                       dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4;
+
+               case 2: /* .....111 11...... ........ ........ ........ */
+                       /* 00000... ........ ........ ........ ........ */
+                       dst[0] = buf[0] << 3 | buf[1] >> 2;
+
+                       break;
+
+               default:
+                       return -1;
+               }
+               dst += (i + 1) / 2;
+
+               if (check_padding) {
+                       /* Check remaining padding characters */
+                       if (ch != '=')
+                               return -1;
+
+                       /* One down, 8 - i - 1 more to come... */
+                       for (i = 8 - i - 1; i > 0; i--) {
+
+                               do {
+                                       if (src_sz == 0)
+                                               return -1;
+                                       ch = *src++;
+                                       src_sz--;
+
+                               } while (isspace((unsigned char)ch));
+
+                               if (ch != '=')
+                                       return -1;
+                       }
+               }
+       }
+       return dst - start;
+}
+
+int
+sldns_b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz)
+{
+       return sldns_b32_pton_base(src, src_sz, dst, dst_sz, 0, 1);
+}
+
+int
+sldns_b32_pton_extended_hex(const char* src, size_t src_sz, 
+               uint8_t* dst, size_t dst_sz)
+{
+       return sldns_b32_pton_base(src, src_sz, dst, dst_sz, 1, 1);
+}
+
+size_t sldns_b64_ntop_calculate_size(size_t srcsize)
+{
+       return ((((srcsize + 2) / 3) * 4) + 1);
+}
+
+/* RFC 1521, section 5.2.
+ *
+ * The encoding process represents 24-bit groups of input bits as output
+ * strings of 4 encoded characters. Proceeding from left to right, a
+ * 24-bit input group is formed by concatenating 3 8-bit input groups.
+ * These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ * of which is translated into a single digit in the base64 alphabet.
+ *
+ * This routine does not insert spaces or linebreaks after 76 characters.
+ */
+int sldns_b64_ntop(uint8_t const *src, size_t srclength,
+       char *target, size_t targsize)
+{
+       const char* b64 =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+       const char pad64 = '=';
+       size_t i = 0, o = 0;
+       if(targsize < sldns_b64_ntop_calculate_size(srclength))
+               return -1;
+       /* whole chunks: xxxxxxyy yyyyzzzz zzwwwwww */
+       while(i+3 <= srclength) {
+               if(o+4 > targsize) return -1;
+               target[o] = b64[src[i] >> 2];
+               target[o+1] = b64[ ((src[i]&0x03)<<4) | (src[i+1]>>4) ];
+               target[o+2] = b64[ ((src[i+1]&0x0f)<<2) | (src[i+2]>>6) ];
+               target[o+3] = b64[ (src[i+2]&0x3f) ];
+               i += 3;
+               o += 4;
+       }
+       /* remainder */
+       switch(srclength - i) {
+       case 2:
+               /* two at end, converted into A B C = */
+               target[o] = b64[src[i] >> 2];
+               target[o+1] = b64[ ((src[i]&0x03)<<4) | (src[i+1]>>4) ];
+               target[o+2] = b64[ ((src[i+1]&0x0f)<<2) ];
+               target[o+3] = pad64;
+               i += 2;
+               o += 4;
+               break;
+       case 1:
+               /* one at end, converted into A B = = */
+               target[o] = b64[src[i] >> 2];
+               target[o+1] = b64[ ((src[i]&0x03)<<4) ];
+               target[o+2] = pad64;
+               target[o+3] = pad64;
+               i += 1;
+               o += 4;
+               break;
+       case 0:
+       default:
+               /* nothing */
+               break;
+       }
+       /* assert: i == srclength */
+       if(o+1 > targsize) return -1;
+       target[o] = 0;
+       return (int)o;
+}
+
+size_t sldns_b64_pton_calculate_size(size_t srcsize)
+{
+       return (((((srcsize + 3) / 4) * 3)) + 1);
+}
+
+int sldns_b64_pton(char const *src, uint8_t *target, size_t targsize)
+{
+       const uint8_t pad64 = 64; /* is 64th in the b64 array */
+       const char* s = src;
+       uint8_t in[4];
+       size_t o = 0, incount = 0;
+
+       while(*s) {
+               /* skip any character that is not base64 */
+               /* conceptually we do:
+               const char* b64 =      pad'=' is appended to array
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+               const char* d = strchr(b64, *s++);
+               and use d-b64;
+               */
+               char d = *s++;
+               if(d <= 'Z' && d >= 'A')
+                       d -= 'A';
+               else if(d <= 'z' && d >= 'a')
+                       d = d - 'a' + 26;
+               else if(d <= '9' && d >= '0')
+                       d = d - '0' + 52;
+               else if(d == '+')
+                       d = 62;
+               else if(d == '/')
+                       d = 63;
+               else if(d == '=')
+                       d = 64;
+               else    continue;
+               in[incount++] = (uint8_t)d;
+               if(incount != 4)
+                       continue;
+               /* process whole block of 4 characters into 3 output bytes */
+               if(in[3] == pad64 && in[2] == pad64) { /* A B = = */
+                       if(o+1 > targsize)
+                               return -1;
+                       target[o] = (in[0]<<2) | ((in[1]&0x30)>>4);
+                       o += 1;
+                       break; /* we are done */
+               } else if(in[3] == pad64) { /* A B C = */
+                       if(o+2 > targsize)
+                               return -1;
+                       target[o] = (in[0]<<2) | ((in[1]&0x30)>>4);
+                       target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2);
+                       o += 2;
+                       break; /* we are done */
+               } else {
+                       if(o+3 > targsize)
+                               return -1;
+                       /* write xxxxxxyy yyyyzzzz zzwwwwww */
+                       target[o] = (in[0]<<2) | ((in[1]&0x30)>>4);
+                       target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2);
+                       target[o+2]= ((in[2]&0x03)<<6) | in[3];
+                       o += 3;
+               }
+               incount = 0;
+       }
+       return (int)o;
+}
diff --git a/sldns/parseutil.h b/sldns/parseutil.h
new file mode 100644 (file)
index 0000000..dfa1c2a
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * parseutil.h - parse utilities for string and wire conversion
+ *
+ * (c) NLnet Labs, 2004
+ *
+ * See the file LICENSE for the license
+ */
+/**
+ * \file
+ *
+ * Utility functions for parsing, base32(DNS variant) and base64 encoding
+ * and decoding, Hex, Time units, Escape codes.
+ */
+
+#ifndef LDNS_PARSEUTIL_H
+#define LDNS_PARSEUTIL_H
+struct tm;
+
+/** 
+ *  A general purpose lookup table
+ *  
+ *  Lookup tables are arrays of (id, name) pairs,
+ *  So you can for instance lookup the RCODE 3, which is "NXDOMAIN",
+ *  and vice versa. The lookup tables themselves are defined wherever needed,
+ *  for instance in host2str.c
+ */
+struct sldns_struct_lookup_table {
+        int id;
+        const char *name;
+};
+typedef struct sldns_struct_lookup_table sldns_lookup_table;
+
+/**
+ * Looks up the table entry by name, returns NULL if not found.
+ * \param[in] table the lookup table to search in
+ * \param[in] name what to search for
+ * \return the item found
+ */
+sldns_lookup_table *sldns_lookup_by_name(sldns_lookup_table table[],
+                                       const char *name);
+/**
+ * Looks up the table entry by id, returns NULL if not found.
+ * \param[in] table the lookup table to search in
+ * \param[in] id what to search for
+ * \return the item found
+ */
+sldns_lookup_table *sldns_lookup_by_id(sldns_lookup_table table[], int id);
+
+/**
+ * Convert TM to seconds since epoch (midnight, January 1st, 1970).
+ * Like timegm(3), which is not always available.
+ * \param[in] tm a struct tm* with the date
+ * \return the seconds since epoch
+ */
+time_t sldns_mktime_from_utc(const struct tm *tm);
+
+/**
+ * The function interprets time as the number of seconds since epoch
+ * with respect to now using serial arithmitics (rfc1982).
+ * That number of seconds is then converted to broken-out time information.
+ * This is especially usefull when converting the inception and expiration
+ * fields of RRSIG records.
+ *
+ * \param[in] time number of seconds since epoch (midnight, January 1st, 1970)
+ *            to be intepreted as a serial arithmitics number relative to now.
+ * \param[in] now number of seconds since epoch (midnight, January 1st, 1970)
+ *            to which the time value is compared to determine the final value.
+ * \param[out] result the struct with the broken-out time information
+ * \return result on success or NULL on error
+ */
+struct tm * sldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result);
+
+/**
+ * converts a ttl value (like 5d2h) to a long.
+ * \param[in] nptr the start of the string
+ * \param[out] endptr points to the last char in case of error
+ * \return the convert duration value
+ */
+uint32_t sldns_str2period(const char *nptr, const char **endptr);
+
+/**
+ * Returns the int value of the given (hex) digit
+ * \param[in] ch the hex char to convert
+ * \return the converted decimal value
+ */
+int sldns_hexdigit_to_int(char ch);
+
+/**
+ * calculates the size needed to store the result of b64_ntop
+ */
+size_t sldns_b64_ntop_calculate_size(size_t srcsize);
+
+int sldns_b64_ntop(uint8_t const *src, size_t srclength,
+       char *target, size_t targsize);
+
+/**
+ * calculates the size needed to store the result of sldns_b64_pton
+ */
+size_t sldns_b64_pton_calculate_size(size_t srcsize);
+
+int sldns_b64_pton(char const *src, uint8_t *target, size_t targsize);
+
+/**
+ * calculates the size needed to store the result of b32_ntop
+ */
+size_t sldns_b32_ntop_calculate_size(size_t src_data_length);
+
+size_t sldns_b32_ntop_calculate_size_no_padding(size_t src_data_length);
+
+int sldns_b32_ntop(const uint8_t* src_data, size_t src_data_length,
+       char* target_text_buffer, size_t target_text_buffer_size);
+
+int sldns_b32_ntop_extended_hex(const uint8_t* src_data, size_t src_data_length,
+       char* target_text_buffer, size_t target_text_buffer_size);
+
+/**
+ * calculates the size needed to store the result of b32_pton
+ */
+size_t sldns_b32_pton_calculate_size(size_t src_text_length);
+
+int sldns_b32_pton(const char* src_text, size_t src_text_length,
+       uint8_t* target_data_buffer, size_t target_data_buffer_size);
+
+int sldns_b32_pton_extended_hex(const char* src_text, size_t src_text_length,
+       uint8_t* target_data_buffer, size_t target_data_buffer_size);
+
+/*
+ * Checks whether the escaped value at **s is an octal value or
+ * a 'normally' escaped character (and not eos)
+ *
+ * @param ch_p: the parsed character
+ * @param str_p: the string. moved along for characters read.
+ * The string pointer at *s is increased by either 0 (on error), 1 (on
+ * normal escapes), or 3 (on octals)
+ *
+ * @return 0 on error
+ */
+int sldns_parse_escape(uint8_t *ch_p, const char** str_p);
+
+/** 
+ * Parse one character, with escape codes,
+ * @param ch_p: the parsed character
+ * @param str_p: the string. moved along for characters read.
+ * @return 0 on error
+ */
+int sldns_parse_char(uint8_t *ch_p, const char** str_p);
+
+#endif /* LDNS_PARSEUTIL_H */
diff --git a/sldns/pkthdr.h b/sldns/pkthdr.h
new file mode 100644 (file)
index 0000000..de9952e
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * pkthdr.h - packet header from wire conversion routines
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Contains functions that translate dns data from the wire format (as sent
+ * by servers and clients) to the internal structures for the packet header.
+ */
+#ifndef LDNS_PKTHDR_H
+#define LDNS_PKTHDR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The length of the header */
+#define        LDNS_HEADER_SIZE        12
+
+/* First octet of flags */
+#define        LDNS_RD_MASK            0x01U
+#define        LDNS_RD_SHIFT   0
+#define        LDNS_RD_WIRE(wirebuf)   (*(wirebuf+2) & LDNS_RD_MASK)
+#define        LDNS_RD_SET(wirebuf)    (*(wirebuf+2) |= LDNS_RD_MASK)
+#define        LDNS_RD_CLR(wirebuf)    (*(wirebuf+2) &= ~LDNS_RD_MASK)
+
+#define LDNS_TC_MASK           0x02U
+#define LDNS_TC_SHIFT  1
+#define        LDNS_TC_WIRE(wirebuf)   (*(wirebuf+2) & LDNS_TC_MASK)
+#define        LDNS_TC_SET(wirebuf)    (*(wirebuf+2) |= LDNS_TC_MASK)
+#define        LDNS_TC_CLR(wirebuf)    (*(wirebuf+2) &= ~LDNS_TC_MASK)
+
+#define        LDNS_AA_MASK            0x04U
+#define        LDNS_AA_SHIFT   2
+#define        LDNS_AA_WIRE(wirebuf)   (*(wirebuf+2) & LDNS_AA_MASK)
+#define        LDNS_AA_SET(wirebuf)    (*(wirebuf+2) |= LDNS_AA_MASK)
+#define        LDNS_AA_CLR(wirebuf)    (*(wirebuf+2) &= ~LDNS_AA_MASK)
+
+#define        LDNS_OPCODE_MASK        0x78U
+#define        LDNS_OPCODE_SHIFT       3
+#define        LDNS_OPCODE_WIRE(wirebuf)       ((*(wirebuf+2) & LDNS_OPCODE_MASK) >> LDNS_OPCODE_SHIFT)
+#define        LDNS_OPCODE_SET(wirebuf, opcode) \
+       (*(wirebuf+2) = ((*(wirebuf+2)) & ~LDNS_OPCODE_MASK) | ((opcode) << LDNS_OPCODE_SHIFT))
+
+#define        LDNS_QR_MASK            0x80U
+#define        LDNS_QR_SHIFT   7
+#define        LDNS_QR_WIRE(wirebuf)   (*(wirebuf+2) & LDNS_QR_MASK)
+#define        LDNS_QR_SET(wirebuf)    (*(wirebuf+2) |= LDNS_QR_MASK)
+#define        LDNS_QR_CLR(wirebuf)    (*(wirebuf+2) &= ~LDNS_QR_MASK)
+
+/* Second octet of flags */
+#define        LDNS_RCODE_MASK 0x0fU
+#define        LDNS_RCODE_SHIFT        0
+#define        LDNS_RCODE_WIRE(wirebuf)        (*(wirebuf+3) & LDNS_RCODE_MASK)
+#define        LDNS_RCODE_SET(wirebuf, rcode) \
+       (*(wirebuf+3) = ((*(wirebuf+3)) & ~LDNS_RCODE_MASK) | (rcode))
+
+#define        LDNS_CD_MASK            0x10U
+#define        LDNS_CD_SHIFT   4
+#define        LDNS_CD_WIRE(wirebuf)   (*(wirebuf+3) & LDNS_CD_MASK)
+#define        LDNS_CD_SET(wirebuf)    (*(wirebuf+3) |= LDNS_CD_MASK)
+#define        LDNS_CD_CLR(wirebuf)    (*(wirebuf+3) &= ~LDNS_CD_MASK)
+
+#define        LDNS_AD_MASK            0x20U
+#define        LDNS_AD_SHIFT   5
+#define        LDNS_AD_WIRE(wirebuf)   (*(wirebuf+3) & LDNS_AD_MASK)
+#define        LDNS_AD_SET(wirebuf)    (*(wirebuf+3) |= LDNS_AD_MASK)
+#define        LDNS_AD_CLR(wirebuf)    (*(wirebuf+3) &= ~LDNS_AD_MASK)
+
+#define        LDNS_Z_MASK             0x40U
+#define        LDNS_Z_SHIFT            6
+#define        LDNS_Z_WIRE(wirebuf)    (*(wirebuf+3) & LDNS_Z_MASK)
+#define        LDNS_Z_SET(wirebuf)     (*(wirebuf+3) |= LDNS_Z_MASK)
+#define        LDNS_Z_CLR(wirebuf)     (*(wirebuf+3) &= ~LDNS_Z_MASK)
+
+#define        LDNS_RA_MASK            0x80U
+#define        LDNS_RA_SHIFT   7
+#define        LDNS_RA_WIRE(wirebuf)   (*(wirebuf+3) & LDNS_RA_MASK)
+#define        LDNS_RA_SET(wirebuf)    (*(wirebuf+3) |= LDNS_RA_MASK)
+#define        LDNS_RA_CLR(wirebuf)    (*(wirebuf+3) &= ~LDNS_RA_MASK)
+
+/* Query ID */
+#define        LDNS_ID_WIRE(wirebuf)           (sldns_read_uint16(wirebuf))
+#define        LDNS_ID_SET(wirebuf, id)        (sldns_write_uint16(wirebuf, id))
+
+/* Counter of the question section */
+#define LDNS_QDCOUNT_OFF               4
+/*
+#define        QDCOUNT(wirebuf)                (ntohs(*(uint16_t *)(wirebuf+QDCOUNT_OFF)))
+*/
+#define        LDNS_QDCOUNT(wirebuf)           (sldns_read_uint16(wirebuf+LDNS_QDCOUNT_OFF))
+
+/* Counter of the answer section */
+#define LDNS_ANCOUNT_OFF               6
+#define        LDNS_ANCOUNT(wirebuf)           (sldns_read_uint16(wirebuf+LDNS_ANCOUNT_OFF))
+
+/* Counter of the authority section */
+#define LDNS_NSCOUNT_OFF               8
+#define        LDNS_NSCOUNT(wirebuf)           (sldns_read_uint16(wirebuf+LDNS_NSCOUNT_OFF))
+
+/* Counter of the additional section */
+#define LDNS_ARCOUNT_OFF               10
+#define        LDNS_ARCOUNT(wirebuf)           (sldns_read_uint16(wirebuf+LDNS_ARCOUNT_OFF))
+
+/**
+ * The sections of a packet
+ */
+enum sldns_enum_pkt_section {
+        LDNS_SECTION_QUESTION = 0,
+        LDNS_SECTION_ANSWER = 1,
+        LDNS_SECTION_AUTHORITY = 2,
+        LDNS_SECTION_ADDITIONAL = 3,
+        /** bogus section, if not interested */
+        LDNS_SECTION_ANY = 4,
+        /** used to get all non-question rrs from a packet */
+        LDNS_SECTION_ANY_NOQUESTION = 5
+};
+typedef enum sldns_enum_pkt_section sldns_pkt_section;
+
+/* opcodes for pkt's */
+enum sldns_enum_pkt_opcode {
+        LDNS_PACKET_QUERY = 0,
+        LDNS_PACKET_IQUERY = 1,
+        LDNS_PACKET_STATUS = 2, /* there is no 3?? DNS is weird */
+        LDNS_PACKET_NOTIFY = 4,
+        LDNS_PACKET_UPDATE = 5
+};
+typedef enum sldns_enum_pkt_opcode sldns_pkt_opcode;
+
+/* rcodes for pkts */
+enum sldns_enum_pkt_rcode {
+        LDNS_RCODE_NOERROR = 0,
+        LDNS_RCODE_FORMERR = 1,
+        LDNS_RCODE_SERVFAIL = 2,
+        LDNS_RCODE_NXDOMAIN = 3,
+        LDNS_RCODE_NOTIMPL = 4,
+        LDNS_RCODE_REFUSED = 5,
+        LDNS_RCODE_YXDOMAIN = 6,
+        LDNS_RCODE_YXRRSET = 7,
+        LDNS_RCODE_NXRRSET = 8,
+        LDNS_RCODE_NOTAUTH = 9,
+        LDNS_RCODE_NOTZONE = 10
+};
+typedef enum sldns_enum_pkt_rcode sldns_pkt_rcode;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_PKTHDR_H */
diff --git a/sldns/rrdef.c b/sldns/rrdef.c
new file mode 100644 (file)
index 0000000..72161d7
--- /dev/null
@@ -0,0 +1,734 @@
+/* rrdef.c
+ *
+ * access functions to rr definitions list.
+ * a Net::DNS like library for C
+ * LibDNS Team @ NLnet Labs
+ *
+ * (c) NLnet Labs, 2004-2006
+ * See the file LICENSE for the license
+ */
+/**
+ * \file
+ *
+ * Defines resource record types and constants.
+ */
+#include "config.h"
+#include "sldns/rrdef.h"
+#include "sldns/parseutil.h"
+
+/* classes  */
+static sldns_lookup_table sldns_rr_classes_data[] = {
+        { LDNS_RR_CLASS_IN, "IN" },
+        { LDNS_RR_CLASS_CH, "CH" },
+        { LDNS_RR_CLASS_HS, "HS" },
+        { LDNS_RR_CLASS_NONE, "NONE" },
+        { LDNS_RR_CLASS_ANY, "ANY" },
+        { 0, NULL }
+};
+sldns_lookup_table* sldns_rr_classes = sldns_rr_classes_data;
+
+/* types */
+static const sldns_rdf_type type_0_wireformat[] = { LDNS_RDF_TYPE_UNKNOWN };
+static const sldns_rdf_type type_a_wireformat[] = { LDNS_RDF_TYPE_A };
+static const sldns_rdf_type type_ns_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_md_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_mf_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_cname_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_soa_wireformat[] = {
+       LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_INT32, 
+       LDNS_RDF_TYPE_PERIOD, LDNS_RDF_TYPE_PERIOD, LDNS_RDF_TYPE_PERIOD,
+       LDNS_RDF_TYPE_PERIOD
+};
+static const sldns_rdf_type type_mb_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_mg_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_mr_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_wks_wireformat[] = {
+       LDNS_RDF_TYPE_A, LDNS_RDF_TYPE_WKS
+};
+static const sldns_rdf_type type_ptr_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_hinfo_wireformat[] = {
+       LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR
+};
+static const sldns_rdf_type type_minfo_wireformat[] = {
+       LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_mx_wireformat[] = {
+       LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_rp_wireformat[] = {
+       LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_afsdb_wireformat[] = {
+       LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_x25_wireformat[] = { LDNS_RDF_TYPE_STR };
+static const sldns_rdf_type type_isdn_wireformat[] = {
+       LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR
+};
+static const sldns_rdf_type type_rt_wireformat[] = {
+       LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_nsap_wireformat[] = {
+       LDNS_RDF_TYPE_NSAP
+};
+static const sldns_rdf_type type_nsap_ptr_wireformat[] = {
+       LDNS_RDF_TYPE_STR
+};
+static const sldns_rdf_type type_sig_wireformat[] = {
+       LDNS_RDF_TYPE_TYPE, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT32,
+       LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_key_wireformat[] = {
+       LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_px_wireformat[] = {
+       LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_gpos_wireformat[] = {
+       LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR
+};
+static const sldns_rdf_type type_aaaa_wireformat[] = { LDNS_RDF_TYPE_AAAA };
+static const sldns_rdf_type type_loc_wireformat[] = { LDNS_RDF_TYPE_LOC };
+static const sldns_rdf_type type_nxt_wireformat[] = {
+       LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_UNKNOWN
+};
+static const sldns_rdf_type type_eid_wireformat[] = {
+       LDNS_RDF_TYPE_HEX
+};
+static const sldns_rdf_type type_nimloc_wireformat[] = {
+       LDNS_RDF_TYPE_HEX
+};
+static const sldns_rdf_type type_srv_wireformat[] = {
+       LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_atma_wireformat[] = {
+       LDNS_RDF_TYPE_ATMA
+};
+static const sldns_rdf_type type_naptr_wireformat[] = {
+       LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_kx_wireformat[] = {
+       LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_cert_wireformat[] = {
+        LDNS_RDF_TYPE_CERT_ALG, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_a6_wireformat[] = { LDNS_RDF_TYPE_UNKNOWN };
+static const sldns_rdf_type type_dname_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_sink_wireformat[] = { LDNS_RDF_TYPE_INT8,
+       LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_apl_wireformat[] = {
+       LDNS_RDF_TYPE_APL
+};
+static const sldns_rdf_type type_ds_wireformat[] = {
+       LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_HEX
+};
+static const sldns_rdf_type type_sshfp_wireformat[] = {
+       LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_HEX
+};
+static const sldns_rdf_type type_ipseckey_wireformat[] = {
+       LDNS_RDF_TYPE_IPSECKEY
+};
+static const sldns_rdf_type type_rrsig_wireformat[] = {
+       LDNS_RDF_TYPE_TYPE, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT32,
+       LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_nsec_wireformat[] = {
+       LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_NSEC
+};
+static const sldns_rdf_type type_dhcid_wireformat[] = {
+       LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_talink_wireformat[] = {
+       LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME
+};
+/* nsec3 is some vars, followed by same type of data of nsec */
+static const sldns_rdf_type type_nsec3_wireformat[] = {
+/*     LDNS_RDF_TYPE_NSEC3_VARS, LDNS_RDF_TYPE_NSEC3_NEXT_OWNER, LDNS_RDF_TYPE_NSEC*/
+       LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_NSEC3_SALT, LDNS_RDF_TYPE_NSEC3_NEXT_OWNER, LDNS_RDF_TYPE_NSEC
+};
+
+static const sldns_rdf_type type_nsec3param_wireformat[] = {
+/*     LDNS_RDF_TYPE_NSEC3_PARAMS_VARS*/
+       LDNS_RDF_TYPE_INT8,
+       LDNS_RDF_TYPE_INT8,
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_NSEC3_SALT
+};
+
+static const sldns_rdf_type type_dnskey_wireformat[] = {
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_INT8,
+       LDNS_RDF_TYPE_ALG,
+       LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_tkey_wireformat[] = {
+       LDNS_RDF_TYPE_DNAME,
+       LDNS_RDF_TYPE_TIME,
+       LDNS_RDF_TYPE_TIME,
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_INT16_DATA,
+       LDNS_RDF_TYPE_INT16_DATA,
+};
+static const sldns_rdf_type type_tsig_wireformat[] = {
+       LDNS_RDF_TYPE_DNAME,
+       LDNS_RDF_TYPE_TSIGTIME,
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_INT16_DATA,
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_INT16_DATA
+};
+static const sldns_rdf_type type_tlsa_wireformat[] = {
+       LDNS_RDF_TYPE_INT8,
+       LDNS_RDF_TYPE_INT8,
+       LDNS_RDF_TYPE_INT8,
+       LDNS_RDF_TYPE_HEX
+};
+static const sldns_rdf_type type_hip_wireformat[] = {
+       LDNS_RDF_TYPE_HIP
+};
+static const sldns_rdf_type type_nid_wireformat[] = {
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_ILNP64
+};
+static const sldns_rdf_type type_l32_wireformat[] = {
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_A
+};
+static const sldns_rdf_type type_l64_wireformat[] = {
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_ILNP64
+};
+static const sldns_rdf_type type_lp_wireformat[] = {
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_eui48_wireformat[] = {
+       LDNS_RDF_TYPE_EUI48
+};
+static const sldns_rdf_type type_eui64_wireformat[] = {
+       LDNS_RDF_TYPE_EUI64
+};
+#ifdef DRAFT_RRTYPES
+static const sldns_rdf_type type_uri_wireformat[] = {
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_LONG_STR
+};
+#endif
+static const sldns_rdf_type type_caa_wireformat[] = {
+       LDNS_RDF_TYPE_INT8,
+       LDNS_RDF_TYPE_TAG,
+       LDNS_RDF_TYPE_LONG_STR
+};
+
+/* All RR's defined in 1035 are well known and can thus
+ * be compressed. See RFC3597. These RR's are:
+ * CNAME HINFO MB MD MF MG MINFO MR MX NULL NS PTR SOA TXT
+ */
+static sldns_rr_descriptor rdata_field_descriptors[] = {
+       /* 0 */
+       { 0, NULL, 0, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 1 */
+       {LDNS_RR_TYPE_A, "A", 1, 1, type_a_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 2 */
+       {LDNS_RR_TYPE_NS, "NS", 1, 1, type_ns_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+       /* 3 */
+       {LDNS_RR_TYPE_MD, "MD", 1, 1, type_md_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+       /* 4 */
+       {LDNS_RR_TYPE_MF, "MF", 1, 1, type_mf_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+       /* 5 */
+       {LDNS_RR_TYPE_CNAME, "CNAME", 1, 1, type_cname_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+       /* 6 */
+       {LDNS_RR_TYPE_SOA, "SOA", 7, 7, type_soa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 2 },
+       /* 7 */
+       {LDNS_RR_TYPE_MB, "MB", 1, 1, type_mb_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+       /* 8 */
+       {LDNS_RR_TYPE_MG, "MG", 1, 1, type_mg_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+       /* 9 */
+       {LDNS_RR_TYPE_MR, "MR", 1, 1, type_mr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+       /* 10 */
+       {LDNS_RR_TYPE_NULL, "NULL", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 11 */
+       {LDNS_RR_TYPE_WKS, "WKS", 2, 2, type_wks_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 12 */
+       {LDNS_RR_TYPE_PTR, "PTR", 1, 1, type_ptr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+       /* 13 */
+       {LDNS_RR_TYPE_HINFO, "HINFO", 2, 2, type_hinfo_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 14 */
+       {LDNS_RR_TYPE_MINFO, "MINFO", 2, 2, type_minfo_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 2 },
+       /* 15 */
+       {LDNS_RR_TYPE_MX, "MX", 2, 2, type_mx_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+       /* 16 */
+       {LDNS_RR_TYPE_TXT, "TXT", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 },
+       /* 17 */
+       {LDNS_RR_TYPE_RP, "RP", 2, 2, type_rp_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 },
+       /* 18 */
+       {LDNS_RR_TYPE_AFSDB, "AFSDB", 2, 2, type_afsdb_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+       /* 19 */
+       {LDNS_RR_TYPE_X25, "X25", 1, 1, type_x25_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 20 */
+       {LDNS_RR_TYPE_ISDN, "ISDN", 1, 2, type_isdn_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 21 */
+       {LDNS_RR_TYPE_RT, "RT", 2, 2, type_rt_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+       /* 22 */
+       {LDNS_RR_TYPE_NSAP, "NSAP", 1, 1, type_nsap_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 23 */
+       {LDNS_RR_TYPE_NSAP_PTR, "NSAP-PTR", 1, 1, type_nsap_ptr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 24 */
+       {LDNS_RR_TYPE_SIG, "SIG", 9, 9, type_sig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+       /* 25 */
+       {LDNS_RR_TYPE_KEY, "KEY", 4, 4, type_key_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 26 */
+       {LDNS_RR_TYPE_PX, "PX", 3, 3, type_px_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 },
+       /* 27 */
+       {LDNS_RR_TYPE_GPOS, "GPOS", 3, 3, type_gpos_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 28 */
+       {LDNS_RR_TYPE_AAAA, "AAAA", 1, 1, type_aaaa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 29 */
+       {LDNS_RR_TYPE_LOC, "LOC", 1, 1, type_loc_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 30 */
+       {LDNS_RR_TYPE_NXT, "NXT", 2, 2, type_nxt_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+       /* 31 */
+       {LDNS_RR_TYPE_EID, "EID", 1, 1, type_eid_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 32 */
+       {LDNS_RR_TYPE_NIMLOC, "NIMLOC", 1, 1, type_nimloc_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 33 */
+       {LDNS_RR_TYPE_SRV, "SRV", 4, 4, type_srv_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+       /* 34 */
+       {LDNS_RR_TYPE_ATMA, "ATMA", 1, 1, type_atma_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 35 */
+       {LDNS_RR_TYPE_NAPTR, "NAPTR", 6, 6, type_naptr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+       /* 36 */
+       {LDNS_RR_TYPE_KX, "KX", 2, 2, type_kx_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+       /* 37 */
+       {LDNS_RR_TYPE_CERT, "CERT", 4, 4, type_cert_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 38 */
+       {LDNS_RR_TYPE_A6, "A6", 1, 1, type_a6_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 39 */
+       {LDNS_RR_TYPE_DNAME, "DNAME", 1, 1, type_dname_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+       /* 40 */
+       {LDNS_RR_TYPE_SINK, "SINK", 1, 1, type_sink_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 41 */
+       {LDNS_RR_TYPE_OPT, "OPT", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 42 */
+       {LDNS_RR_TYPE_APL, "APL", 0, 0, type_apl_wireformat, LDNS_RDF_TYPE_APL, LDNS_RR_NO_COMPRESS, 0 },
+       /* 43 */
+       {LDNS_RR_TYPE_DS, "DS", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 44 */
+       {LDNS_RR_TYPE_SSHFP, "SSHFP", 3, 3, type_sshfp_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 45 */
+       {LDNS_RR_TYPE_IPSECKEY, "IPSECKEY", 1, 1, type_ipseckey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 46 */
+       {LDNS_RR_TYPE_RRSIG, "RRSIG", 9, 9, type_rrsig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+       /* 47 */
+       {LDNS_RR_TYPE_NSEC, "NSEC", 1, 2, type_nsec_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+       /* 48 */
+       {LDNS_RR_TYPE_DNSKEY, "DNSKEY", 4, 4, type_dnskey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 49 */
+       {LDNS_RR_TYPE_DHCID, "DHCID", 1, 1, type_dhcid_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 50 */
+       {LDNS_RR_TYPE_NSEC3, "NSEC3", 5, 6, type_nsec3_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 51 */
+       {LDNS_RR_TYPE_NSEC3PARAM, "NSEC3PARAM", 4, 4, type_nsec3param_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 52 */
+       {LDNS_RR_TYPE_TLSA, "TLSA", 4, 4, type_tlsa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+{LDNS_RR_TYPE_NULL, "TYPE53", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE54", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+        /* 55
+        * Hip ends with 0 or more Rendezvous Servers represented as dname's.
+        * Hence the LDNS_RDF_TYPE_DNAME _variable field and the _maximum field
+        * set to 0.
+        */
+       {LDNS_RR_TYPE_HIP, "HIP", 1, 1, type_hip_wireformat, LDNS_RDF_TYPE_DNAME, LDNS_RR_NO_COMPRESS, 0 },
+
+#ifdef DRAFT_RRTYPES
+       /* 56 */
+       {LDNS_RR_TYPE_NINFO, "NINFO", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 },
+       /* 57 */
+       {LDNS_RR_TYPE_RKEY, "RKEY", 4, 4, type_key_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+#else
+{LDNS_RR_TYPE_NULL, "TYPE56", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE57", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+#endif
+       /* 58 */
+       {LDNS_RR_TYPE_TALINK, "TALINK", 2, 2, type_talink_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 },
+
+       /* 59 */
+       {LDNS_RR_TYPE_CDS, "CDS", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 60 */
+       {LDNS_RR_TYPE_CDNSKEY, "CDNSKEY", 4, 4, type_dnskey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE61", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE62", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE63", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE64", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE65", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE66", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE67", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE68", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE69", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE70", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE71", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE72", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE73", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE74", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE75", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE76", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE77", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE78", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE79", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE80", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE81", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE82", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE83", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE84", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE85", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE86", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE87", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE88", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE89", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE90", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE91", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE92", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE93", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE94", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE95", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE96", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE97", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE98", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+       /* 99 */
+       {LDNS_RR_TYPE_SPF,  "SPF", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 },
+
+       /* UINFO  [IANA-Reserved] */
+{LDNS_RR_TYPE_NULL, "TYPE100", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* UID    [IANA-Reserved] */
+{LDNS_RR_TYPE_NULL, "TYPE101", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* GID    [IANA-Reserved] */
+{LDNS_RR_TYPE_NULL, "TYPE102", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* UNSPEC [IANA-Reserved] */
+{LDNS_RR_TYPE_NULL, "TYPE103", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+       /* 104 */
+       {LDNS_RR_TYPE_NID, "NID", 2, 2, type_nid_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 105 */
+       {LDNS_RR_TYPE_L32, "L32", 2, 2, type_l32_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 106 */
+       {LDNS_RR_TYPE_L64, "L64", 2, 2, type_l64_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 107 */
+       {LDNS_RR_TYPE_LP, "LP", 2, 2, type_lp_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+
+       /* 108 */
+       {LDNS_RR_TYPE_EUI48, "EUI48", 1, 1, type_eui48_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* 109 */
+       {LDNS_RR_TYPE_EUI64, "EUI64", 1, 1, type_eui64_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+{LDNS_RR_TYPE_NULL, "TYPE110", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE111", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE112", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE113", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE114", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE115", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE116", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE117", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE118", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE119", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE120", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE121", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE122", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE123", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE124", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE125", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE126", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE127", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE128", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE129", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE130", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE131", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE132", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE133", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE134", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE135", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE136", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE137", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE138", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE139", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE140", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE141", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE142", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE143", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE144", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE145", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE146", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE147", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE148", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE149", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE150", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE151", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE152", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE153", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE154", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE155", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE156", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE157", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE158", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE159", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE160", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE161", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE162", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE163", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE164", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE165", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE166", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE167", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE168", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE169", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE170", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE171", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE172", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE173", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE174", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE175", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE176", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE177", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE178", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE179", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE180", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE181", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE182", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE183", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE184", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE185", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE186", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE187", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE188", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE189", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE190", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE191", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE192", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE193", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE194", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE195", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE196", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE197", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE198", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE199", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE200", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE201", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE202", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE203", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE204", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE205", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE206", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE207", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE208", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE209", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE210", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE211", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE212", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE213", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE214", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE215", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE216", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE217", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE218", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE219", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE220", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE221", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE222", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE223", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE224", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE225", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE226", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE227", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE228", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE229", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE230", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE231", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE232", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE233", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE234", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE235", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE236", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE237", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE238", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE239", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE240", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE241", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE242", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE243", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE244", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE245", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE246", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE247", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE248", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+       /* LDNS_RDF_TYPE_INT16_DATA takes two fields (length and data) as one.
+        * So, unlike RFC 2930 spec, we have 7 min/max rdf's i.s.o. 8/9.
+        */
+       /* 249 */
+       {LDNS_RR_TYPE_TKEY, "TKEY", 7, 7, type_tkey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+       /* LDNS_RDF_TYPE_INT16_DATA takes two fields (length and data) as one.
+        * So, unlike RFC 2930 spec, we have 7 min/max rdf's i.s.o. 8/9.
+        */
+       /* 250 */
+       {LDNS_RR_TYPE_TSIG, "TSIG", 7, 7, type_tsig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+
+       /* IXFR: A request for a transfer of an incremental zone transfer */
+{LDNS_RR_TYPE_IXFR, "IXFR", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* AXFR: A request for a transfer of an entire zone */
+{LDNS_RR_TYPE_AXFR, "AXFR", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* MAILB: A request for mailbox-related records (MB, MG or MR) */
+{LDNS_RR_TYPE_MAILB, "MAILB", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* MAILA: A request for mail agent RRs (Obsolete - see MX) */
+{LDNS_RR_TYPE_MAILA, "MAILA", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+       /* ANY: A request for all (available) records */
+{LDNS_RR_TYPE_ANY, "ANY", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+#ifdef DRAFT_RRTYPES
+       /* 256 */
+       {LDNS_RR_TYPE_URI, "URI", 3, 3, type_uri_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+#else
+{LDNS_RR_TYPE_NULL, "TYPE256", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+#endif
+       /* 257 */
+       {LDNS_RR_TYPE_CAA, "CAA", 3, 3, type_caa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+/* split in array, no longer contiguous */
+
+#ifdef DRAFT_RRTYPES
+       /* 32768 */
+       {LDNS_RR_TYPE_TA, "TA", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+#else
+{LDNS_RR_TYPE_NULL, "TYPE32768", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+#endif
+       /* 32769 */
+       {LDNS_RR_TYPE_DLV, "DLV", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }
+};
+
+/**
+ * \def LDNS_RDATA_FIELD_DESCRIPTORS_COUNT
+ * computes the number of rdata fields
+ */
+#define LDNS_RDATA_FIELD_DESCRIPTORS_COUNT \
+       (sizeof(rdata_field_descriptors)/sizeof(rdata_field_descriptors[0]))
+
+const sldns_rr_descriptor *
+sldns_rr_descript(uint16_t type)
+{
+       size_t i;
+       if (type < LDNS_RDATA_FIELD_DESCRIPTORS_COMMON) {
+               return &rdata_field_descriptors[type];
+       } else {
+               /* because not all array index equals type code */
+               for (i = LDNS_RDATA_FIELD_DESCRIPTORS_COMMON;
+                    i < LDNS_RDATA_FIELD_DESCRIPTORS_COUNT;
+                    i++) {
+                       if (rdata_field_descriptors[i]._type == type) {
+                               return &rdata_field_descriptors[i];
+                       }
+               }
+                return &rdata_field_descriptors[0];
+       }
+}
+
+size_t
+sldns_rr_descriptor_minimum(const sldns_rr_descriptor *descriptor)
+{
+       if (descriptor) {
+               return descriptor->_minimum;
+       } else {
+               return 0;
+       }
+}
+
+size_t
+sldns_rr_descriptor_maximum(const sldns_rr_descriptor *descriptor)
+{
+       if (descriptor) {
+               if (descriptor->_variable != LDNS_RDF_TYPE_NONE) {
+                       return 65535; /* cannot be more than 64k */
+               } else {
+                       return descriptor->_maximum;
+               }
+       } else {
+               return 0;
+       }
+}
+
+sldns_rdf_type
+sldns_rr_descriptor_field_type(const sldns_rr_descriptor *descriptor,
+                              size_t index)
+{
+       assert(descriptor != NULL);
+       assert(index < descriptor->_maximum
+              || descriptor->_variable != LDNS_RDF_TYPE_NONE);
+       if (index < descriptor->_maximum) {
+               return descriptor->_wireformat[index];
+       } else {
+               return descriptor->_variable;
+       }
+}
+
+sldns_rr_type
+sldns_get_rr_type_by_name(const char *name)
+{
+       unsigned int i;
+       const char *desc_name;
+       const sldns_rr_descriptor *desc;
+
+       /* TYPEXX representation */
+       if (strlen(name) > 4 && strncasecmp(name, "TYPE", 4) == 0) {
+               return atoi(name + 4);
+       }
+
+       /* Normal types */
+       for (i = 0; i < (unsigned int) LDNS_RDATA_FIELD_DESCRIPTORS_COUNT; i++) {
+               desc = &rdata_field_descriptors[i];
+               desc_name = desc->_name;
+               if(desc_name &&
+                  strlen(name) == strlen(desc_name) &&
+                  strncasecmp(name, desc_name, strlen(desc_name)) == 0) {
+                       /* because not all array index equals type code */
+                       return desc->_type;
+               }
+       }
+
+       /* special cases for query types */
+       if (strlen(name) == 4 && strncasecmp(name, "IXFR", 4) == 0) {
+               return 251;
+       } else if (strlen(name) == 4 && strncasecmp(name, "AXFR", 4) == 0) {
+               return 252;
+       } else if (strlen(name) == 5 && strncasecmp(name, "MAILB", 5) == 0) {
+               return 253;
+       } else if (strlen(name) == 5 && strncasecmp(name, "MAILA", 5) == 0) {
+               return 254;
+       } else if (strlen(name) == 3 && strncasecmp(name, "ANY", 3) == 0) {
+               return 255;
+       }
+
+       return 0;
+}
+
+sldns_rr_class
+sldns_get_rr_class_by_name(const char *name)
+{
+       sldns_lookup_table *lt;
+
+       /* CLASSXX representation */
+       if (strlen(name) > 5 && strncasecmp(name, "CLASS", 5) == 0) {
+               return atoi(name + 5);
+       }
+
+       /* Normal types */
+       lt = sldns_lookup_by_name(sldns_rr_classes, name);
+       if (lt) {
+               return lt->id;
+       }
+       return 0;
+}
diff --git a/sldns/rrdef.h b/sldns/rrdef.h
new file mode 100644 (file)
index 0000000..933bcdf
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * rrdef.h
+ *
+ * RR definitions
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Defines resource record types and constants.
+ */
+
+#ifndef LDNS_RRDEF_H
+#define LDNS_RRDEF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Maximum length of a dname label */
+#define LDNS_MAX_LABELLEN     63
+/** Maximum length of a complete dname */
+#define LDNS_MAX_DOMAINLEN    255
+/** Maximum number of pointers in 1 dname */
+#define LDNS_MAX_POINTERS      65535
+/** The bytes TTL, CLASS and length use up in an rr */
+#define LDNS_RR_OVERHEAD       10
+
+#define LDNS_DNSSEC_KEYPROTO    3
+#define LDNS_KEY_ZONE_KEY   0x0100 /* set for ZSK&KSK, rfc 4034 */
+#define LDNS_KEY_SEP_KEY    0x0001 /* set for KSK, rfc 4034 */
+#define LDNS_KEY_REVOKE_KEY 0x0080 /* used to revoke KSK, rfc 5011 */
+
+/* The first fields are contiguous and can be referenced instantly */
+#define LDNS_RDATA_FIELD_DESCRIPTORS_COMMON 258
+
+/** lookuptable for rr classes  */
+extern struct sldns_struct_lookup_table* sldns_rr_classes;
+
+/**
+ *  The different RR classes.
+ */
+enum sldns_enum_rr_class
+{
+       /** the Internet */
+       LDNS_RR_CLASS_IN        = 1,
+       /** Chaos class */
+       LDNS_RR_CLASS_CH        = 3,
+       /** Hesiod (Dyer 87) */
+       LDNS_RR_CLASS_HS        = 4,
+       /** None class, dynamic update */
+       LDNS_RR_CLASS_NONE      = 254,
+       /** Any class */
+       LDNS_RR_CLASS_ANY       = 255,
+
+       LDNS_RR_CLASS_FIRST     = 0,
+       LDNS_RR_CLASS_LAST      = 65535,
+       LDNS_RR_CLASS_COUNT     = LDNS_RR_CLASS_LAST - LDNS_RR_CLASS_FIRST + 1
+};
+typedef enum sldns_enum_rr_class sldns_rr_class;
+
+/**
+ *  Used to specify whether compression is allowed.
+ */
+enum sldns_enum_rr_compress
+{
+       /** compression is allowed */
+       LDNS_RR_COMPRESS,
+       LDNS_RR_NO_COMPRESS
+};
+typedef enum sldns_enum_rr_compress sldns_rr_compress;
+
+/**
+ * The different RR types.
+ */
+enum sldns_enum_rr_type
+{
+       /**  a host address */
+       LDNS_RR_TYPE_A = 1,
+       /**  an authoritative name server */
+       LDNS_RR_TYPE_NS = 2,
+       /**  a mail destination (Obsolete - use MX) */
+       LDNS_RR_TYPE_MD = 3,
+       /**  a mail forwarder (Obsolete - use MX) */
+       LDNS_RR_TYPE_MF = 4,
+       /**  the canonical name for an alias */
+       LDNS_RR_TYPE_CNAME = 5,
+       /**  marks the start of a zone of authority */
+       LDNS_RR_TYPE_SOA = 6,
+       /**  a mailbox domain name (EXPERIMENTAL) */
+       LDNS_RR_TYPE_MB = 7,
+       /**  a mail group member (EXPERIMENTAL) */
+       LDNS_RR_TYPE_MG = 8,
+       /**  a mail rename domain name (EXPERIMENTAL) */
+       LDNS_RR_TYPE_MR = 9,
+       /**  a null RR (EXPERIMENTAL) */
+       LDNS_RR_TYPE_NULL = 10,
+       /**  a well known service description */
+       LDNS_RR_TYPE_WKS = 11,
+       /**  a domain name pointer */
+       LDNS_RR_TYPE_PTR = 12,
+       /**  host information */
+       LDNS_RR_TYPE_HINFO = 13,
+       /**  mailbox or mail list information */
+       LDNS_RR_TYPE_MINFO = 14,
+       /**  mail exchange */
+       LDNS_RR_TYPE_MX = 15,
+       /**  text strings */
+       LDNS_RR_TYPE_TXT = 16,
+       /**  RFC1183 */
+       LDNS_RR_TYPE_RP = 17,
+       /**  RFC1183 */
+       LDNS_RR_TYPE_AFSDB = 18,
+       /**  RFC1183 */
+       LDNS_RR_TYPE_X25 = 19,
+       /**  RFC1183 */
+       LDNS_RR_TYPE_ISDN = 20,
+       /**  RFC1183 */
+       LDNS_RR_TYPE_RT = 21,
+       /**  RFC1706 */
+       LDNS_RR_TYPE_NSAP = 22,
+       /**  RFC1348 */
+       LDNS_RR_TYPE_NSAP_PTR = 23,
+       /**  2535typecode */
+       LDNS_RR_TYPE_SIG = 24,
+       /**  2535typecode */
+       LDNS_RR_TYPE_KEY = 25,
+       /**  RFC2163 */
+       LDNS_RR_TYPE_PX = 26,
+       /**  RFC1712 */
+       LDNS_RR_TYPE_GPOS = 27,
+       /**  ipv6 address */
+       LDNS_RR_TYPE_AAAA = 28,
+       /**  LOC record  RFC1876 */
+       LDNS_RR_TYPE_LOC = 29,
+       /**  2535typecode */
+       LDNS_RR_TYPE_NXT = 30,
+       /**  draft-ietf-nimrod-dns-01.txt */
+       LDNS_RR_TYPE_EID = 31,
+       /**  draft-ietf-nimrod-dns-01.txt */
+       LDNS_RR_TYPE_NIMLOC = 32,
+       /**  SRV record RFC2782 */
+       LDNS_RR_TYPE_SRV = 33,
+       /**  http://www.jhsoft.com/rfc/af-saa-0069.000.rtf */
+       LDNS_RR_TYPE_ATMA = 34,
+       /**  RFC2915 */
+       LDNS_RR_TYPE_NAPTR = 35,
+       /**  RFC2230 */
+       LDNS_RR_TYPE_KX = 36,
+       /**  RFC2538 */
+       LDNS_RR_TYPE_CERT = 37,
+       /**  RFC2874 */
+       LDNS_RR_TYPE_A6 = 38,
+       /**  RFC2672 */
+       LDNS_RR_TYPE_DNAME = 39,
+       /**  dnsind-kitchen-sink-02.txt */
+       LDNS_RR_TYPE_SINK = 40,
+       /**  Pseudo OPT record... */
+       LDNS_RR_TYPE_OPT = 41,
+       /**  RFC3123 */
+       LDNS_RR_TYPE_APL = 42,
+       /**  RFC4034, RFC3658 */
+       LDNS_RR_TYPE_DS = 43,
+       /**  SSH Key Fingerprint */
+       LDNS_RR_TYPE_SSHFP = 44, /* RFC 4255 */
+       /**  IPsec Key */
+       LDNS_RR_TYPE_IPSECKEY = 45, /* RFC 4025 */
+       /**  DNSSEC */
+       LDNS_RR_TYPE_RRSIG = 46, /* RFC 4034 */
+       LDNS_RR_TYPE_NSEC = 47, /* RFC 4034 */
+       LDNS_RR_TYPE_DNSKEY = 48, /* RFC 4034 */
+
+       LDNS_RR_TYPE_DHCID = 49, /* RFC 4701 */
+       /* NSEC3 */
+       LDNS_RR_TYPE_NSEC3 = 50, /* RFC 5155 */
+       LDNS_RR_TYPE_NSEC3PARAM = 51, /* RFC 5155 */
+       LDNS_RR_TYPE_NSEC3PARAMS = 51,
+       LDNS_RR_TYPE_TLSA = 52, /* RFC 6698 */
+
+       LDNS_RR_TYPE_HIP = 55, /* RFC 5205 */
+
+       /** draft-reid-dnsext-zs */
+       LDNS_RR_TYPE_NINFO = 56,
+       /** draft-reid-dnsext-rkey */
+       LDNS_RR_TYPE_RKEY = 57,
+        /** draft-ietf-dnsop-trust-history */
+        LDNS_RR_TYPE_TALINK = 58,
+       LDNS_RR_TYPE_CDS = 59, /** RFC 7344 */
+       LDNS_RR_TYPE_CDNSKEY = 60, /** RFC 7344 */
+
+       LDNS_RR_TYPE_SPF = 99, /* RFC 4408 */
+
+       LDNS_RR_TYPE_UINFO = 100,
+       LDNS_RR_TYPE_UID = 101,
+       LDNS_RR_TYPE_GID = 102,
+       LDNS_RR_TYPE_UNSPEC = 103,
+
+       LDNS_RR_TYPE_NID = 104, /* RFC 6742 */
+       LDNS_RR_TYPE_L32 = 105, /* RFC 6742 */
+       LDNS_RR_TYPE_L64 = 106, /* RFC 6742 */
+       LDNS_RR_TYPE_LP = 107, /* RFC 6742 */
+
+       /** draft-jabley-dnsext-eui48-eui64-rrtypes */
+       LDNS_RR_TYPE_EUI48 = 108,
+       LDNS_RR_TYPE_EUI64 = 109,
+
+       LDNS_RR_TYPE_TKEY = 249, /* RFC 2930 */
+       LDNS_RR_TYPE_TSIG = 250,
+       LDNS_RR_TYPE_IXFR = 251,
+       LDNS_RR_TYPE_AXFR = 252,
+       /**  A request for mailbox-related records (MB, MG or MR) */
+       LDNS_RR_TYPE_MAILB = 253,
+       /**  A request for mail agent RRs (Obsolete - see MX) */
+       LDNS_RR_TYPE_MAILA = 254,
+       /**  any type (wildcard) */
+       LDNS_RR_TYPE_ANY = 255,
+       /** draft-faltstrom-uri-06 */
+       LDNS_RR_TYPE_URI = 256,
+       LDNS_RR_TYPE_CAA = 257, /* RFC 6844 */
+
+       /** DNSSEC Trust Authorities */
+       LDNS_RR_TYPE_TA = 32768,
+       /* RFC 4431, 5074, DNSSEC Lookaside Validation */
+       LDNS_RR_TYPE_DLV = 32769,
+
+       /* type codes from nsec3 experimental phase
+       LDNS_RR_TYPE_NSEC3 = 65324,
+       LDNS_RR_TYPE_NSEC3PARAMS = 65325, */
+       LDNS_RR_TYPE_FIRST = 0,
+       LDNS_RR_TYPE_LAST  = 65535,
+       LDNS_RR_TYPE_COUNT = LDNS_RR_TYPE_LAST - LDNS_RR_TYPE_FIRST + 1
+};
+typedef enum sldns_enum_rr_type sldns_rr_type;
+
+/* RDATA */
+#define LDNS_MAX_RDFLEN        65535
+
+#define LDNS_RDF_SIZE_BYTE              1
+#define LDNS_RDF_SIZE_WORD              2
+#define LDNS_RDF_SIZE_DOUBLEWORD        4
+#define LDNS_RDF_SIZE_6BYTES            6
+#define LDNS_RDF_SIZE_8BYTES            8
+#define LDNS_RDF_SIZE_16BYTES           16
+
+#define LDNS_NSEC3_VARS_OPTOUT_MASK 0x01
+
+#define LDNS_APL_IP4            1
+#define LDNS_APL_IP6            2
+#define LDNS_APL_MASK           0x7f
+#define LDNS_APL_NEGATION       0x80
+
+/**
+ * The different types of RDATA fields.
+ */
+enum sldns_enum_rdf_type
+{
+       /** none */
+       LDNS_RDF_TYPE_NONE,
+       /** domain name */
+       LDNS_RDF_TYPE_DNAME,
+       /** 8 bits */
+       LDNS_RDF_TYPE_INT8,
+       /** 16 bits */
+       LDNS_RDF_TYPE_INT16,
+       /** 32 bits */
+       LDNS_RDF_TYPE_INT32,
+       /** A record */
+       LDNS_RDF_TYPE_A,
+       /** AAAA record */
+       LDNS_RDF_TYPE_AAAA,
+       /** txt string */
+       LDNS_RDF_TYPE_STR,
+       /** apl data */
+       LDNS_RDF_TYPE_APL,
+       /** b32 string */
+       LDNS_RDF_TYPE_B32_EXT,
+       /** b64 string */
+       LDNS_RDF_TYPE_B64,
+       /** hex string */
+       LDNS_RDF_TYPE_HEX,
+       /** nsec type codes */
+       LDNS_RDF_TYPE_NSEC,
+       /** a RR type */
+       LDNS_RDF_TYPE_TYPE,
+       /** a class */
+       LDNS_RDF_TYPE_CLASS,
+       /** certificate algorithm */
+       LDNS_RDF_TYPE_CERT_ALG,
+       /** a key algorithm */
+        LDNS_RDF_TYPE_ALG,
+        /** unknown types */
+        LDNS_RDF_TYPE_UNKNOWN,
+        /** time (32 bits) */
+        LDNS_RDF_TYPE_TIME,
+        /** period */
+        LDNS_RDF_TYPE_PERIOD,
+        /** tsig time 48 bits */
+        LDNS_RDF_TYPE_TSIGTIME,
+       /** Represents the Public Key Algorithm, HIT and Public Key fields
+           for the HIP RR types.  A HIP specific rdf type is used because of
+           the unusual layout in wireformat (see RFC 5205 Section 5) */
+       LDNS_RDF_TYPE_HIP,
+        /** variable length any type rdata where the length
+            is specified by the first 2 bytes */
+        LDNS_RDF_TYPE_INT16_DATA,
+        /** protocol and port bitmaps */
+        LDNS_RDF_TYPE_SERVICE,
+        /** location data */
+        LDNS_RDF_TYPE_LOC,
+        /** well known services */
+        LDNS_RDF_TYPE_WKS,
+        /** NSAP */
+        LDNS_RDF_TYPE_NSAP,
+        /** ATMA */
+        LDNS_RDF_TYPE_ATMA,
+        /** IPSECKEY */
+        LDNS_RDF_TYPE_IPSECKEY,
+        /** nsec3 hash salt */
+        LDNS_RDF_TYPE_NSEC3_SALT,
+        /** nsec3 base32 string (with length byte on wire */
+        LDNS_RDF_TYPE_NSEC3_NEXT_OWNER,
+
+        /** 4 shorts represented as 4 * 16 bit hex numbers
+         *  seperated by colons. For NID and L64.
+         */
+        LDNS_RDF_TYPE_ILNP64,
+
+        /** 6 * 8 bit hex numbers seperated by dashes. For EUI48. */
+        LDNS_RDF_TYPE_EUI48,
+        /** 8 * 8 bit hex numbers seperated by dashes. For EUI64. */
+        LDNS_RDF_TYPE_EUI64,
+
+        /** A non-zero sequence of US-ASCII letters and numbers in lower case.
+         *  For CAA.
+         */
+        LDNS_RDF_TYPE_TAG,
+
+        /** A <character-string> encoding of the value field as specified 
+         * [RFC1035], Section 5.1., encoded as remaining rdata.
+         * For CAA.
+         */
+        LDNS_RDF_TYPE_LONG_STR,
+
+        /* Aliases */
+        LDNS_RDF_TYPE_BITMAP = LDNS_RDF_TYPE_NSEC
+};
+typedef enum sldns_enum_rdf_type sldns_rdf_type;
+
+/**
+ * Algorithms used in dns
+ */
+enum sldns_enum_algorithm
+{
+        LDNS_RSAMD5             = 1,   /* RFC 4034,4035 */
+        LDNS_DH                 = 2,
+        LDNS_DSA                = 3,
+        LDNS_ECC                = 4,
+        LDNS_RSASHA1            = 5,
+        LDNS_DSA_NSEC3          = 6,
+        LDNS_RSASHA1_NSEC3      = 7,
+        LDNS_RSASHA256          = 8,   /* RFC 5702 */
+        LDNS_RSASHA512          = 10,  /* RFC 5702 */
+        LDNS_ECC_GOST           = 12,  /* RFC 5933 */
+        LDNS_ECDSAP256SHA256    = 13,  /* RFC 6605 */
+        LDNS_ECDSAP384SHA384    = 14,  /* RFC 6605 */
+        LDNS_INDIRECT           = 252,
+        LDNS_PRIVATEDNS         = 253,
+        LDNS_PRIVATEOID         = 254
+};
+typedef enum sldns_enum_algorithm sldns_algorithm;
+
+/**
+ * Hashing algorithms used in the DS record
+ */
+enum sldns_enum_hash
+{
+        LDNS_SHA1               = 1,  /* RFC 4034 */
+        LDNS_SHA256             = 2,  /* RFC 4509 */
+        LDNS_HASH_GOST          = 3,  /* RFC 5933 */
+        LDNS_SHA384             = 4   /* RFC 6605 */
+};
+typedef enum sldns_enum_hash sldns_hash;
+
+/**
+ * algorithms used in CERT rrs
+ */
+enum sldns_enum_cert_algorithm
+{
+        LDNS_CERT_PKIX          = 1,
+        LDNS_CERT_SPKI          = 2,
+        LDNS_CERT_PGP           = 3,
+        LDNS_CERT_IPKIX         = 4,
+        LDNS_CERT_ISPKI         = 5,
+        LDNS_CERT_IPGP          = 6,
+        LDNS_CERT_ACPKIX        = 7,
+        LDNS_CERT_IACPKIX       = 8,
+        LDNS_CERT_URI           = 253,
+        LDNS_CERT_OID           = 254
+};
+typedef enum sldns_enum_cert_algorithm sldns_cert_algorithm;
+
+/**
+ * EDNS option codes
+ */
+enum sldns_enum_edns_option
+{
+       LDNS_EDNS_LLQ = 1, /* http://files.dns-sd.org/draft-sekar-dns-llq.txt */
+       LDNS_EDNS_UL = 2, /* http://files.dns-sd.org/draft-sekar-dns-ul.txt */
+       LDNS_EDNS_NSID = 3, /* RFC5001 */
+       /* 4 draft-cheshire-edns0-owner-option */
+       LDNS_EDNS_DAU = 5, /* RFC6975 */
+       LDNS_EDNS_DHU = 6, /* RFC6975 */
+       LDNS_EDNS_N3U = 7, /* RFC6975 */
+       LDNS_EDNS_CLIENT_SUBNET = 8 /* draft-vandergaast-edns-client-subnet */
+};
+typedef enum sldns_enum_edns_option sldns_edns_option;
+
+#define LDNS_EDNS_MASK_DO_BIT 0x8000
+
+/**
+ * Contains all information about resource record types.
+ *
+ * This structure contains, for all rr types, the rdata fields that are defined.
+ */
+struct sldns_struct_rr_descriptor
+{
+       /** Type of the RR that is described here */
+       sldns_rr_type    _type;
+       /** Textual name of the RR type.  */
+       const char *_name;
+       /** Minimum number of rdata fields in the RRs of this type.  */
+       uint8_t     _minimum;
+       /** Maximum number of rdata fields in the RRs of this type.  */
+       uint8_t     _maximum;
+       /** Wireformat specification for the rr, i.e. the types of rdata fields in their respective order. */
+       const sldns_rdf_type *_wireformat;
+       /** Special rdf types */
+       sldns_rdf_type _variable;
+       /** Specifies whether compression can be used for dnames in this RR type. */
+       sldns_rr_compress _compress;
+       /** The number of DNAMEs in the _wireformat string, for parsing. */
+       uint8_t _dname_count;
+};
+typedef struct sldns_struct_rr_descriptor sldns_rr_descriptor;
+
+/**
+ * returns the resource record descriptor for the given rr type.
+ *
+ * \param[in] type the type value of the rr type
+ *\return the sldns_rr_descriptor for this type
+ */
+const sldns_rr_descriptor *sldns_rr_descript(uint16_t type);
+
+/**
+ * returns the minimum number of rdata fields of the rr type this descriptor describes.
+ *
+ * \param[in]  descriptor for an rr type
+ * \return the minimum number of rdata fields
+ */
+size_t sldns_rr_descriptor_minimum(const sldns_rr_descriptor *descriptor);
+
+/**
+ * returns the maximum number of rdata fields of the rr type this descriptor describes.
+ *
+ * \param[in]  descriptor for an rr type
+ * \return the maximum number of rdata fields
+ */
+size_t sldns_rr_descriptor_maximum(const sldns_rr_descriptor *descriptor);
+
+/**
+ * returns the rdf type for the given rdata field number of the rr type for the given descriptor.
+ *
+ * \param[in] descriptor for an rr type
+ * \param[in] field the field number
+ * \return the rdf type for the field
+ */
+sldns_rdf_type sldns_rr_descriptor_field_type(const sldns_rr_descriptor *descriptor, size_t field);
+
+/**
+ * retrieves a rrtype by looking up its name.
+ * \param[in] name a string with the name
+ * \return the type which corresponds with the name
+ */
+sldns_rr_type sldns_get_rr_type_by_name(const char *name);
+
+/**
+ * retrieves a class by looking up its name.
+ * \param[in] name string with the name
+ * \return the cass which corresponds with the name
+ */
+sldns_rr_class sldns_get_rr_class_by_name(const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_RRDEF_H */
diff --git a/sldns/sbuffer.c b/sldns/sbuffer.c
new file mode 100644 (file)
index 0000000..a7fe53a
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * buffer.c -- generic memory buffer .
+ *
+ * Copyright (c) 2001-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ *
+ */
+/**
+ * \file
+ *
+ * This file contains the definition of sldns_buffer, and functions to manipulate those.
+ */
+#include "config.h"
+#include "sldns/sbuffer.h"
+#include <stdarg.h>
+
+sldns_buffer *
+sldns_buffer_new(size_t capacity)
+{
+       sldns_buffer *buffer = (sldns_buffer*)malloc(sizeof(sldns_buffer));
+
+       if (!buffer) {
+               return NULL;
+       }
+       
+       buffer->_data = (uint8_t *) malloc(capacity);
+       if (!buffer->_data) {
+               free(buffer);
+               return NULL;
+       }
+       
+       buffer->_position = 0;
+       buffer->_limit = buffer->_capacity = capacity;
+       buffer->_fixed = 0;
+       buffer->_status_err = 0;
+       
+       sldns_buffer_invariant(buffer);
+       
+       return buffer;
+}
+
+void
+sldns_buffer_new_frm_data(sldns_buffer *buffer, void *data, size_t size)
+{
+       assert(data != NULL);
+
+       buffer->_position = 0; 
+       buffer->_limit = buffer->_capacity = size;
+       buffer->_fixed = 0;
+       buffer->_data = malloc(size);
+       if(!buffer->_data) {
+               buffer->_status_err = 1;
+               return;
+       }
+       memcpy(buffer->_data, data, size);
+       buffer->_status_err = 0;
+       
+       sldns_buffer_invariant(buffer);
+}
+
+void
+sldns_buffer_init_frm_data(sldns_buffer *buffer, void *data, size_t size)
+{
+       memset(buffer, 0, sizeof(*buffer));
+       buffer->_data = data;
+       buffer->_capacity = buffer->_limit = size;
+       buffer->_fixed = 1;
+}
+
+int
+sldns_buffer_set_capacity(sldns_buffer *buffer, size_t capacity)
+{
+       void *data;
+       
+       sldns_buffer_invariant(buffer);
+       assert(buffer->_position <= capacity);
+
+       data = (uint8_t *) realloc(buffer->_data, capacity);
+       if (!data) {
+               buffer->_status_err = 1;
+               return 0;
+       } else {
+               buffer->_data = data;
+               buffer->_limit = buffer->_capacity = capacity;
+               return 1;
+       }
+}
+
+int
+sldns_buffer_reserve(sldns_buffer *buffer, size_t amount)
+{
+       sldns_buffer_invariant(buffer);
+       assert(!buffer->_fixed);
+       if (buffer->_capacity < buffer->_position + amount) {
+               size_t new_capacity = buffer->_capacity * 3 / 2;
+
+               if (new_capacity < buffer->_position + amount) {
+                       new_capacity = buffer->_position + amount;
+               }
+               if (!sldns_buffer_set_capacity(buffer, new_capacity)) {
+                       buffer->_status_err = 1;
+                       return 0;
+               }
+       }
+       buffer->_limit = buffer->_capacity;
+       return 1;
+}
+
+int
+sldns_buffer_printf(sldns_buffer *buffer, const char *format, ...)
+{
+       va_list args;
+       int written = 0;
+       size_t remaining;
+       
+       if (sldns_buffer_status_ok(buffer)) {
+               sldns_buffer_invariant(buffer);
+               assert(buffer->_limit == buffer->_capacity);
+
+               remaining = sldns_buffer_remaining(buffer);
+               va_start(args, format);
+               written = vsnprintf((char *) sldns_buffer_current(buffer), remaining,
+                                   format, args);
+               va_end(args);
+               if (written == -1) {
+                       buffer->_status_err = 1;
+                       return -1;
+               } else if ((size_t) written >= remaining) {
+                       if (!sldns_buffer_reserve(buffer, (size_t) written + 1)) {
+                               buffer->_status_err = 1;
+                               return -1;
+                       }
+                       va_start(args, format);
+                       written = vsnprintf((char *) sldns_buffer_current(buffer),
+                           sldns_buffer_remaining(buffer), format, args);
+                       va_end(args);
+                       if (written == -1) {
+                               buffer->_status_err = 1;
+                               return -1;
+                       }
+               }
+               buffer->_position += written;
+       }
+       return written;
+}
+
+void
+sldns_buffer_free(sldns_buffer *buffer)
+{
+       if (!buffer) {
+               return;
+       }
+
+       if (!buffer->_fixed)
+               free(buffer->_data);
+
+       free(buffer);
+}
+
+void *
+sldns_buffer_export(sldns_buffer *buffer)
+{
+       buffer->_fixed = 1;
+       return buffer->_data;
+}
+
+void 
+sldns_buffer_copy(sldns_buffer* result, sldns_buffer* from)
+{
+       size_t tocopy = sldns_buffer_limit(from);
+
+       if(tocopy > sldns_buffer_capacity(result))
+               tocopy = sldns_buffer_capacity(result);
+       sldns_buffer_clear(result);
+       sldns_buffer_write(result, sldns_buffer_begin(from), tocopy);
+       sldns_buffer_flip(result);
+}
diff --git a/sldns/sbuffer.h b/sldns/sbuffer.h
new file mode 100644 (file)
index 0000000..3ce874f
--- /dev/null
@@ -0,0 +1,706 @@
+/*
+ * buffer.h -- generic memory buffer.
+ *
+ * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ *
+ *
+ * The buffer module implements a generic buffer.  The API is based on
+ * the java.nio.Buffer interface.
+ */
+
+#ifndef LDNS_SBUFFER_H
+#define LDNS_SBUFFER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef S_SPLINT_S
+#  define INLINE 
+#else
+#  ifdef SWIG
+#    define INLINE static
+#  else
+#    define INLINE static inline
+#  endif
+#endif
+
+/*
+ * Copy data allowing for unaligned accesses in network byte order
+ * (big endian).
+ */
+INLINE uint16_t
+sldns_read_uint16(const void *src)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+        return ntohs(*(const uint16_t *) src);
+#else
+        const uint8_t *p = (const uint8_t *) src;
+        return ((uint16_t) p[0] << 8) | (uint16_t) p[1];
+#endif
+}
+
+INLINE uint32_t
+sldns_read_uint32(const void *src)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+        return ntohl(*(const uint32_t *) src);
+#else
+        const uint8_t *p = (const uint8_t *) src;
+        return (  ((uint32_t) p[0] << 24)
+                | ((uint32_t) p[1] << 16)
+                | ((uint32_t) p[2] << 8)
+                |  (uint32_t) p[3]);
+#endif
+}
+
+/*
+ * Copy data allowing for unaligned accesses in network byte order
+ * (big endian).
+ */
+INLINE void
+sldns_write_uint16(void *dst, uint16_t data)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+        * (uint16_t *) dst = htons(data);
+#else
+        uint8_t *p = (uint8_t *) dst;
+        p[0] = (uint8_t) ((data >> 8) & 0xff);
+        p[1] = (uint8_t) (data & 0xff);
+#endif
+}
+
+INLINE void
+sldns_write_uint32(void *dst, uint32_t data)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+        * (uint32_t *) dst = htonl(data);
+#else
+        uint8_t *p = (uint8_t *) dst;
+        p[0] = (uint8_t) ((data >> 24) & 0xff);
+        p[1] = (uint8_t) ((data >> 16) & 0xff);
+        p[2] = (uint8_t) ((data >> 8) & 0xff);
+        p[3] = (uint8_t) (data & 0xff);
+#endif
+}
+
+
+/**
+ * \file sbuffer.h
+ *
+ * This file contains the definition of sldns_buffer, and functions to manipulate those.
+ */
+
+/** 
+ * implementation of buffers to ease operations
+ *
+ * sldns_buffers can contain arbitrary information, per octet. You can write
+ * to the current end of a buffer, read from the current position, and
+ * access any data within it.
+ */
+struct sldns_buffer
+{
+       /** The current position used for reading/writing */ 
+       size_t   _position;
+
+       /** The read/write limit */
+       size_t   _limit;
+
+       /** The amount of data the buffer can contain */
+       size_t   _capacity;
+
+       /** The data contained in the buffer */
+       uint8_t *_data;
+
+       /** If the buffer is fixed it cannot be resized */
+       unsigned _fixed : 1;
+
+       /** The current state of the buffer. If writing to the buffer fails
+        * for any reason, this value is changed. This way, you can perform
+        * multiple writes in sequence and check for success afterwards. */
+       unsigned _status_err : 1;
+};
+typedef struct sldns_buffer sldns_buffer;
+
+#ifdef NDEBUG
+INLINE void
+sldns_buffer_invariant(sldns_buffer *ATTR_UNUSED(buffer))
+{
+}
+#else
+INLINE void
+sldns_buffer_invariant(sldns_buffer *buffer)
+{
+       assert(buffer != NULL);
+       assert(buffer->_position <= buffer->_limit);
+       assert(buffer->_limit <= buffer->_capacity);
+       assert(buffer->_data != NULL);
+}
+#endif
+
+/**
+ * creates a new buffer with the specified capacity.
+ *
+ * \param[in] capacity the size (in bytes) to allocate for the buffer
+ * \return the created buffer
+ */
+sldns_buffer *sldns_buffer_new(size_t capacity);
+
+/**
+ * creates a buffer with the specified data.  The data IS copied
+ * and MEMORY allocations are done.  The buffer is not fixed and can
+ * be resized using buffer_reserve().
+ *
+ * \param[in] buffer pointer to the buffer to put the data in
+ * \param[in] data the data to encapsulate in the buffer
+ * \param[in] size the size of the data
+ */
+void sldns_buffer_new_frm_data(sldns_buffer *buffer, void *data, size_t size);
+
+/**
+ * Setup a buffer with the data pointed to. No data copied, no memory allocs.
+ * The buffer is fixed.
+ * \param[in] buffer pointer to the buffer to put the data in
+ * \param[in] data the data to encapsulate in the buffer
+ * \param[in] size the size of the data
+ */
+void sldns_buffer_init_frm_data(sldns_buffer *buffer, void *data, size_t size);
+
+/**
+ * clears the buffer and make it ready for writing.  The buffer's limit
+ * is set to the capacity and the position is set to 0.
+ * \param[in] buffer the buffer to clear
+ */
+INLINE void sldns_buffer_clear(sldns_buffer *buffer)
+{
+       sldns_buffer_invariant(buffer);
+
+       /* reset status here? */
+
+       buffer->_position = 0;
+       buffer->_limit = buffer->_capacity;
+}
+
+/**
+ * makes the buffer ready for reading the data that has been written to
+ * the buffer.  The buffer's limit is set to the current position and
+ * the position is set to 0.
+ *
+ * \param[in] buffer the buffer to flip
+ * \return void
+ */
+INLINE void sldns_buffer_flip(sldns_buffer *buffer)
+{
+       sldns_buffer_invariant(buffer);
+
+       buffer->_limit = buffer->_position;
+       buffer->_position = 0;
+}
+
+/**
+ * make the buffer ready for re-reading the data.  The buffer's
+ * position is reset to 0.
+ * \param[in] buffer the buffer to rewind
+ */
+INLINE void sldns_buffer_rewind(sldns_buffer *buffer)
+{
+       sldns_buffer_invariant(buffer);
+
+       buffer->_position = 0;
+}
+
+/**
+ * returns the current position in the buffer (as a number of bytes)
+ * \param[in] buffer the buffer
+ * \return the current position
+ */
+INLINE size_t
+sldns_buffer_position(sldns_buffer *buffer)
+{
+       return buffer->_position;
+}
+
+/**
+ * sets the buffer's position to MARK.  The position must be less than
+ * or equal to the buffer's limit.
+ * \param[in] buffer the buffer
+ * \param[in] mark the mark to use
+ */
+INLINE void
+sldns_buffer_set_position(sldns_buffer *buffer, size_t mark)
+{
+       assert(mark <= buffer->_limit);
+       buffer->_position = mark;
+}
+
+/**
+ * changes the buffer's position by COUNT bytes.  The position must not
+ * be moved behind the buffer's limit or before the beginning of the
+ * buffer.
+ * \param[in] buffer the buffer
+ * \param[in] count the count to use
+ */
+INLINE void
+sldns_buffer_skip(sldns_buffer *buffer, ssize_t count)
+{
+       assert(buffer->_position + count <= buffer->_limit);
+       buffer->_position += count;
+}
+
+/**
+ * returns the maximum size of the buffer
+ * \param[in] buffer
+ * \return the size
+ */
+INLINE size_t
+sldns_buffer_limit(sldns_buffer *buffer)
+{
+       return buffer->_limit;
+}
+
+/**
+ * changes the buffer's limit.  If the buffer's position is greater
+ * than the new limit the position is set to the limit.
+ * \param[in] buffer the buffer
+ * \param[in] limit the new limit
+ */
+INLINE void
+sldns_buffer_set_limit(sldns_buffer *buffer, size_t limit)
+{
+       assert(limit <= buffer->_capacity);
+       buffer->_limit = limit;
+       if (buffer->_position > buffer->_limit)
+               buffer->_position = buffer->_limit;
+}
+
+/**
+ * returns the number of bytes the buffer can hold.
+ * \param[in] buffer the buffer
+ * \return the number of bytes
+ */
+INLINE size_t
+sldns_buffer_capacity(sldns_buffer *buffer)
+{
+       return buffer->_capacity;
+}
+
+/**
+ * changes the buffer's capacity.  The data is reallocated so any
+ * pointers to the data may become invalid.  The buffer's limit is set
+ * to the buffer's new capacity.
+ * \param[in] buffer the buffer
+ * \param[in] capacity the capacity to use
+ * \return whether this failed or succeeded
+ */
+int sldns_buffer_set_capacity(sldns_buffer *buffer, size_t capacity);
+
+/**
+ * ensures BUFFER can contain at least AMOUNT more bytes.  The buffer's
+ * capacity is increased if necessary using buffer_set_capacity().
+ *
+ * The buffer's limit is always set to the (possibly increased)
+ * capacity.
+ * \param[in] buffer the buffer
+ * \param[in] amount amount to use
+ * \return whether this failed or succeeded
+ */
+int sldns_buffer_reserve(sldns_buffer *buffer, size_t amount);
+
+/**
+ * returns a pointer to the data at the indicated position.
+ * \param[in] buffer the buffer
+ * \param[in] at position
+ * \return the pointer to the data
+ */
+INLINE uint8_t *
+sldns_buffer_at(const sldns_buffer *buffer, size_t at)
+{
+       assert(at <= buffer->_limit);
+       return buffer->_data + at;
+}
+
+/**
+ * returns a pointer to the beginning of the buffer (the data at
+ * position 0).
+ * \param[in] buffer the buffer
+ * \return the pointer
+ */
+INLINE uint8_t *
+sldns_buffer_begin(const sldns_buffer *buffer)
+{
+       return sldns_buffer_at(buffer, 0);
+}
+
+/**
+ * returns a pointer to the end of the buffer (the data at the buffer's
+ * limit).
+ * \param[in] buffer the buffer
+ * \return the pointer
+ */
+INLINE uint8_t *
+sldns_buffer_end(sldns_buffer *buffer)
+{
+       return sldns_buffer_at(buffer, buffer->_limit);
+}
+
+/**
+ * returns a pointer to the data at the buffer's current position.
+ * \param[in] buffer the buffer
+ * \return the pointer
+ */
+INLINE uint8_t *
+sldns_buffer_current(sldns_buffer *buffer)
+{
+       return sldns_buffer_at(buffer, buffer->_position);
+}
+
+/**
+ * returns the number of bytes remaining between the indicated position and
+ * the limit.
+ * \param[in] buffer the buffer
+ * \param[in] at indicated position
+ * \return number of bytes
+ */
+INLINE size_t
+sldns_buffer_remaining_at(sldns_buffer *buffer, size_t at)
+{
+       sldns_buffer_invariant(buffer);
+       assert(at <= buffer->_limit);
+       return buffer->_limit - at;
+}
+
+/**
+ * returns the number of bytes remaining between the buffer's position and
+ * limit.
+ * \param[in] buffer the buffer
+ * \return the number of bytes
+ */
+INLINE size_t
+sldns_buffer_remaining(sldns_buffer *buffer)
+{
+       return sldns_buffer_remaining_at(buffer, buffer->_position);
+}
+
+/**
+ * checks if the buffer has at least COUNT more bytes available.
+ * Before reading or writing the caller needs to ensure enough space
+ * is available!
+ * \param[in] buffer the buffer
+ * \param[in] at indicated position
+ * \param[in] count how much is available
+ * \return true or false (as int?)
+ */
+INLINE int
+sldns_buffer_available_at(sldns_buffer *buffer, size_t at, size_t count)
+{
+       return count <= sldns_buffer_remaining_at(buffer, at);
+}
+
+/**
+ * checks if the buffer has count bytes available at the current position
+ * \param[in] buffer the buffer
+ * \param[in] count how much is available
+ * \return true or false (as int?)
+ */
+INLINE int
+sldns_buffer_available(sldns_buffer *buffer, size_t count)
+{
+       return sldns_buffer_available_at(buffer, buffer->_position, count);
+}
+
+/**
+ * writes the given data to the buffer at the specified position
+ * \param[in] buffer the buffer
+ * \param[in] at the position (in number of bytes) to write the data at
+ * \param[in] data pointer to the data to write to the buffer
+ * \param[in] count the number of bytes of data to write
+ */
+INLINE void
+sldns_buffer_write_at(sldns_buffer *buffer, size_t at, const void *data, size_t count)
+{
+       assert(sldns_buffer_available_at(buffer, at, count));
+       memcpy(buffer->_data + at, data, count);
+}
+
+/**
+ * writes count bytes of data to the current position of the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the data to write
+ * \param[in] count the lenght of the data to write
+ */
+INLINE void
+sldns_buffer_write(sldns_buffer *buffer, const void *data, size_t count)
+{
+       sldns_buffer_write_at(buffer, buffer->_position, data, count);
+       buffer->_position += count;
+}
+
+/**
+ * copies the given (null-delimited) string to the specified position at the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] str the string to write
+ */
+INLINE void
+sldns_buffer_write_string_at(sldns_buffer *buffer, size_t at, const char *str)
+{
+       sldns_buffer_write_at(buffer, at, str, strlen(str));
+}
+
+/**
+ * copies the given (null-delimited) string to the current position at the buffer
+ * \param[in] buffer the buffer
+ * \param[in] str the string to write
+ */
+INLINE void
+sldns_buffer_write_string(sldns_buffer *buffer, const char *str)
+{
+       sldns_buffer_write(buffer, str, strlen(str));
+}
+
+/**
+ * writes the given byte of data at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] data the 8 bits to write
+ */
+INLINE void
+sldns_buffer_write_u8_at(sldns_buffer *buffer, size_t at, uint8_t data)
+{
+       assert(sldns_buffer_available_at(buffer, at, sizeof(data)));
+       buffer->_data[at] = data;
+}
+
+/**
+ * writes the given byte of data at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the 8 bits to write
+ */
+INLINE void
+sldns_buffer_write_u8(sldns_buffer *buffer, uint8_t data)
+{
+       sldns_buffer_write_u8_at(buffer, buffer->_position, data);
+       buffer->_position += sizeof(data);
+}
+
+/**
+ * writes the given 2 byte integer at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] data the 16 bits to write
+ */
+INLINE void
+sldns_buffer_write_u16_at(sldns_buffer *buffer, size_t at, uint16_t data)
+{
+       assert(sldns_buffer_available_at(buffer, at, sizeof(data)));
+       sldns_write_uint16(buffer->_data + at, data);
+}
+
+/**
+ * writes the given 2 byte integer at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the 16 bits to write
+ */
+INLINE void
+sldns_buffer_write_u16(sldns_buffer *buffer, uint16_t data)
+{
+       sldns_buffer_write_u16_at(buffer, buffer->_position, data);
+       buffer->_position += sizeof(data);
+}
+
+/**
+ * writes the given 4 byte integer at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] data the 32 bits to write
+ */
+INLINE void
+sldns_buffer_write_u32_at(sldns_buffer *buffer, size_t at, uint32_t data)
+{
+       assert(sldns_buffer_available_at(buffer, at, sizeof(data)));
+       sldns_write_uint32(buffer->_data + at, data);
+}
+
+/**
+ * writes the given 4 byte integer at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the 32 bits to write
+ */
+INLINE void
+sldns_buffer_write_u32(sldns_buffer *buffer, uint32_t data)
+{
+       sldns_buffer_write_u32_at(buffer, buffer->_position, data);
+       buffer->_position += sizeof(data);
+}
+
+/**
+ * copies count bytes of data at the given position to the given data-array
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer to start
+ * \param[out] data buffer to copy to
+ * \param[in] count the length of the data to copy
+ */
+INLINE void
+sldns_buffer_read_at(sldns_buffer *buffer, size_t at, void *data, size_t count)
+{
+       assert(sldns_buffer_available_at(buffer, at, count));
+       memcpy(data, buffer->_data + at, count);
+}
+
+/**
+ * copies count bytes of data at the current position to the given data-array
+ * \param[in] buffer the buffer
+ * \param[out] data buffer to copy to
+ * \param[in] count the length of the data to copy
+ */
+INLINE void
+sldns_buffer_read(sldns_buffer *buffer, void *data, size_t count)
+{
+       sldns_buffer_read_at(buffer, buffer->_position, data, count);
+       buffer->_position += count;
+}
+
+/**
+ * returns the byte value at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \return 1 byte integer
+ */
+INLINE uint8_t
+sldns_buffer_read_u8_at(sldns_buffer *buffer, size_t at)
+{
+       assert(sldns_buffer_available_at(buffer, at, sizeof(uint8_t)));
+       return buffer->_data[at];
+}
+
+/**
+ * returns the byte value at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \return 1 byte integer
+ */
+INLINE uint8_t
+sldns_buffer_read_u8(sldns_buffer *buffer)
+{
+       uint8_t result = sldns_buffer_read_u8_at(buffer, buffer->_position);
+       buffer->_position += sizeof(uint8_t);
+       return result;
+}
+
+/**
+ * returns the 2-byte integer value at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at position in the buffer
+ * \return 2 byte integer
+ */
+INLINE uint16_t
+sldns_buffer_read_u16_at(sldns_buffer *buffer, size_t at)
+{
+       assert(sldns_buffer_available_at(buffer, at, sizeof(uint16_t)));
+       return sldns_read_uint16(buffer->_data + at);
+}
+
+/**
+ * returns the 2-byte integer value at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \return 2 byte integer
+ */
+INLINE uint16_t
+sldns_buffer_read_u16(sldns_buffer *buffer)
+{
+       uint16_t result = sldns_buffer_read_u16_at(buffer, buffer->_position);
+       buffer->_position += sizeof(uint16_t);
+       return result;
+}
+
+/**
+ * returns the 4-byte integer value at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at position in the buffer
+ * \return 4 byte integer
+ */
+INLINE uint32_t
+sldns_buffer_read_u32_at(sldns_buffer *buffer, size_t at)
+{
+       assert(sldns_buffer_available_at(buffer, at, sizeof(uint32_t)));
+       return sldns_read_uint32(buffer->_data + at);
+}
+
+/**
+ * returns the 4-byte integer value at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \return 4 byte integer
+ */
+INLINE uint32_t
+sldns_buffer_read_u32(sldns_buffer *buffer)
+{
+       uint32_t result = sldns_buffer_read_u32_at(buffer, buffer->_position);
+       buffer->_position += sizeof(uint32_t);
+       return result;
+}
+
+/**
+ * returns the status of the buffer
+ * \param[in] buffer
+ * \return the status
+ */
+INLINE int
+sldns_buffer_status(sldns_buffer *buffer)
+{
+       return (int)buffer->_status_err;
+}
+
+/**
+ * returns true if the status of the buffer is LDNS_STATUS_OK, false otherwise
+ * \param[in] buffer the buffer
+ * \return true or false
+ */
+INLINE int
+sldns_buffer_status_ok(sldns_buffer *buffer)
+{
+       if (buffer) {
+               return sldns_buffer_status(buffer) == 0;
+       } else {
+               return 0;
+       }
+}
+
+/**
+ * prints to the buffer, increasing the capacity if required using
+ * buffer_reserve(). The buffer's position is set to the terminating '\\0'
+ * Returns the number of characters written (not including the
+ * terminating '\\0') or -1 on failure.
+ */
+int sldns_buffer_printf(sldns_buffer *buffer, const char *format, ...)
+       ATTR_FORMAT(printf, 2, 3);
+
+/**
+ * frees the buffer.
+ * \param[in] *buffer the buffer to be freed
+ * \return void
+ */
+void sldns_buffer_free(sldns_buffer *buffer);
+
+/**
+ * Makes the buffer fixed and returns a pointer to the data.  The
+ * caller is responsible for free'ing the result.
+ * \param[in] *buffer the buffer to be exported
+ * \return void
+ */
+void *sldns_buffer_export(sldns_buffer *buffer);
+
+/**
+ * Copy contents of the from buffer to the result buffer and then flips 
+ * the result buffer. Data will be silently truncated if the result buffer is
+ * too small.
+ * \param[out] *result resulting buffer which is copied to.
+ * \param[in] *from what to copy to result.
+ */
+void sldns_buffer_copy(sldns_buffer* result, sldns_buffer* from);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_SBUFFER_H */
diff --git a/sldns/str2wire.c b/sldns/str2wire.c
new file mode 100644 (file)
index 0000000..8cda8c7
--- /dev/null
@@ -0,0 +1,2023 @@
+/**
+ * str2wire.c - read txt presentation of RRs
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Parses text to wireformat.
+ */
+#include "config.h"
+#include "sldns/str2wire.h"
+#include "sldns/wire2str.h"
+#include "sldns/sbuffer.h"
+#include "sldns/parse.h"
+#include "sldns/parseutil.h"
+#include <ctype.h>
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+/** return an error */
+#define RET_ERR(e, off) ((int)((e)|((off)<<LDNS_WIREPARSE_SHIFT)))
+/** Move parse error but keep its ID */
+#define RET_ERR_SHIFT(e, move) RET_ERR(LDNS_WIREPARSE_ERROR(e), LDNS_WIREPARSE_OFFSET(e)+(move));
+#define LDNS_IP6ADDRLEN      (128/8)
+
+/*
+ * No special care is taken, all dots are translated into
+ * label separators.
+ * @param rel: true if the domain is not absolute (not terminated in .).
+ *     The output is then still terminated with a '0' rootlabel.
+ */
+static int sldns_str2wire_dname_buf_rel(const char* str, uint8_t* buf,
+       size_t* olen, int* rel)
+{
+       size_t len;
+
+       const char *s;
+       uint8_t *q, *pq, label_len;
+
+       if(rel) *rel = 0;
+       len = strlen((char*)str);
+       /* octet representation can make strings a lot longer than actual length */
+       if (len > LDNS_MAX_DOMAINLEN * 4) {
+               return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, 0);
+       }
+       if (0 == len) {
+               return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_UNDERFLOW, 0);
+       }
+
+       /* root label */
+       if (1 == len && *str == '.') {
+               if(*olen < 1)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 0);
+               buf[0] = 0;
+               *olen = 1;
+               return LDNS_WIREPARSE_ERR_OK;
+       }
+
+       /* get on with the rest */
+
+       /* s is on the current character in the string
+         * pq points to where the labellength is going to go
+         * label_len keeps track of the current label's length
+        * q builds the dname inside the buf array
+        */
+       len = 0;
+       if(*olen < 1)
+               return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 0);
+       q = buf+1;
+       pq = buf;
+       label_len = 0;
+       for (s = str; *s; s++, q++) {
+               if (q >= buf + *olen)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf);
+               if (q > buf + LDNS_MAX_DOMAINLEN)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf);
+               switch (*s) {
+               case '.':
+                       if (label_len > LDNS_MAX_LABELLEN) {
+                               return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, q-buf);
+                       }
+                       if (label_len == 0) {
+                               return RET_ERR(LDNS_WIREPARSE_ERR_EMPTY_LABEL, q-buf);
+                       }
+                       len += label_len + 1;
+                       *q = 0;
+                       *pq = label_len;
+                       label_len = 0;
+                       pq = q;
+                       break;
+               case '\\':
+                       /* octet value or literal char */
+                       s += 1;
+                       if (!sldns_parse_escape(q, &s)) {
+                               *q = 0;
+                               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE, q-buf);
+                       }
+                       s -= 1;
+                       label_len++;
+                       break;
+               default:
+                       *q = (uint8_t)*s;
+                       label_len++;
+               }
+       }
+
+       /* add root label if last char was not '.' */
+       if(label_len != 0) {
+               if(rel) *rel = 1;
+               if (q >= buf + *olen)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf);
+               if (q > buf + LDNS_MAX_DOMAINLEN) {
+                       return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf);
+               }
+                if (label_len > LDNS_MAX_LABELLEN) {
+                        return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, q-buf);
+                }
+                if (label_len == 0) { /* label_len 0 but not . at end? */
+                        return RET_ERR(LDNS_WIREPARSE_ERR_EMPTY_LABEL, q-buf);
+                }
+               len += label_len + 1;
+               *pq = label_len;
+               *q = 0;
+       }
+       len++;
+       *olen = len;
+
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_dname_buf(const char* str, uint8_t* buf, size_t* len)
+{
+       return sldns_str2wire_dname_buf_rel(str, buf, len, NULL);
+}
+
+int sldns_str2wire_dname_buf_origin(const char* str, uint8_t* buf, size_t* len,
+       uint8_t* origin, size_t origin_len)
+{
+       size_t dlen = *len;
+       int rel = 0;
+       int s = sldns_str2wire_dname_buf_rel(str, buf, &dlen, &rel);
+       if(s) return s;
+
+       if(rel && origin && dlen > 0) {
+               if(dlen + origin_len - 1 > LDNS_MAX_DOMAINLEN)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW,
+                               LDNS_MAX_DOMAINLEN);
+               if(dlen + origin_len - 1 > *len)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                               *len);
+               memmove(buf+dlen-1, origin, origin_len);
+               *len = dlen + origin_len - 1;
+       } else
+               *len = dlen;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+uint8_t* sldns_str2wire_dname(const char* str, size_t* len)
+{
+       uint8_t dname[LDNS_MAX_DOMAINLEN+1];
+       *len = sizeof(dname);
+       if(sldns_str2wire_dname_buf(str, dname, len) == 0) {
+               uint8_t* r = (uint8_t*)malloc(*len);
+               if(r) return memcpy(r, dname, *len);
+       }
+       *len = 0;
+       return NULL;
+}
+
+/** read owner name */
+static int
+rrinternal_get_owner(sldns_buffer* strbuf, uint8_t* rr, size_t* len,
+       size_t* dname_len, uint8_t* origin, size_t origin_len, uint8_t* prev,
+       size_t prev_len, char* token, size_t token_len)
+{
+       /* split the rr in its parts -1 signals trouble */
+       if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
+               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX,
+                       sldns_buffer_position(strbuf));
+       }
+
+       if(strcmp(token, "@") == 0) {
+               uint8_t* tocopy;
+               if (origin) {
+                       *dname_len = origin_len;
+                       tocopy = origin;
+               } else if (prev) {
+                       *dname_len = prev_len;
+                       tocopy = prev;
+               } else {
+                       /* default to root */
+                       *dname_len = 1;
+                       tocopy = (uint8_t*)"\0";
+               }
+               if(*len < *dname_len)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                               sldns_buffer_position(strbuf));
+               memmove(rr, tocopy, *dname_len);
+       } else if(strlen(token) == 0) {
+               /* no ownername was given, try prev, if that fails
+                * origin, else default to root */
+               uint8_t* tocopy;
+               if(prev) {
+                       *dname_len = prev_len;
+                       tocopy = prev;
+               } else if(origin) {
+                       *dname_len = origin_len;
+                       tocopy = origin;
+               } else {
+                       *dname_len = 1;
+                       tocopy = (uint8_t*)"\0";
+               }
+               if(*len < *dname_len)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                               sldns_buffer_position(strbuf));
+               memmove(rr, tocopy, *dname_len);
+       } else {
+               size_t dlen = *len;
+               int s = sldns_str2wire_dname_buf_origin(token, rr, &dlen,
+                       origin, origin_len);
+               if(s) return RET_ERR_SHIFT(s,
+                       sldns_buffer_position(strbuf)-strlen(token));
+               *dname_len = dlen;
+       }
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** read ttl */
+static int
+rrinternal_get_ttl(sldns_buffer* strbuf, char* token, size_t token_len,
+       int* not_there, uint32_t* ttl, uint32_t default_ttl)
+{
+       const char* endptr;
+       if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
+               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TTL,
+                       sldns_buffer_position(strbuf));
+       }
+       *ttl = (uint32_t) sldns_str2period(token, &endptr);
+
+       if (strlen(token) > 0 && !isdigit((unsigned char)token[0])) {
+               *not_there = 1;
+               /* ah, it's not there or something */
+               if (default_ttl == 0) {
+                       *ttl = LDNS_DEFAULT_TTL;
+               } else {
+                       *ttl = default_ttl;
+               }
+       }
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** read class */
+static int
+rrinternal_get_class(sldns_buffer* strbuf, char* token, size_t token_len,
+       int* not_there, uint16_t* cl)
+{
+       /* if 'not_there' then we got token from previous parse routine */
+       if(!*not_there) {
+               /* parse new token for class */
+               if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
+                       return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_CLASS,
+                               sldns_buffer_position(strbuf));
+               }
+       } else *not_there = 0;
+       *cl = sldns_get_rr_class_by_name(token);
+       /* class can be left out too, assume IN, current token must be type */
+       if(*cl == 0 && strcmp(token, "CLASS0") != 0) {
+               *not_there = 1;
+               *cl = LDNS_RR_CLASS_IN;
+       }
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** read type */
+static int
+rrinternal_get_type(sldns_buffer* strbuf, char* token, size_t token_len,
+       int* not_there, uint16_t* tp)
+{
+       /* if 'not_there' then we got token from previous parse routine */
+       if(!*not_there) {
+               /* parse new token for type */
+               if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
+                       return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE,
+                               sldns_buffer_position(strbuf));
+               }
+       }
+       *tp = sldns_get_rr_type_by_name(token);
+       if(*tp == 0 && strcmp(token, "TYPE0") != 0) {
+               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE,
+                       sldns_buffer_position(strbuf));
+       }
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** put type, class, ttl into rr buffer */
+static int
+rrinternal_write_typeclassttl(sldns_buffer* strbuf, uint8_t* rr, size_t len,
+       size_t dname_len, uint16_t tp, uint16_t cl, uint32_t ttl, int question)
+{
+       if(question) {
+               /* question is : name, type, class */
+               if(dname_len + 4 > len)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                               sldns_buffer_position(strbuf));
+               sldns_write_uint16(rr+dname_len, tp);
+               sldns_write_uint16(rr+dname_len+2, cl);
+               return LDNS_WIREPARSE_ERR_OK;
+       }
+
+       /* type(2), class(2), ttl(4), rdatalen(2 (later)) = 10 */
+       if(dname_len + 10 > len)
+               return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                       sldns_buffer_position(strbuf));
+       sldns_write_uint16(rr+dname_len, tp);
+       sldns_write_uint16(rr+dname_len+2, cl);
+       sldns_write_uint32(rr+dname_len+4, ttl);
+       sldns_write_uint16(rr+dname_len+8, 0); /* rdatalen placeholder */
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** find delimiters for type */
+static const char*
+rrinternal_get_delims(sldns_rdf_type rdftype, uint16_t r_cnt, uint16_t r_max)
+{
+       switch(rdftype) {
+       case LDNS_RDF_TYPE_B64        :
+       case LDNS_RDF_TYPE_HEX        : /* These rdf types may con- */
+       case LDNS_RDF_TYPE_LOC        : /* tain whitespace, only if */
+       case LDNS_RDF_TYPE_WKS        : /* it is the last rd field. */
+       case LDNS_RDF_TYPE_IPSECKEY   :
+       case LDNS_RDF_TYPE_NSEC       : if (r_cnt == r_max - 1) {
+                                               return "\n";
+                                       }
+                                       break;
+       default                       : break;
+       }
+       return "\n\t "; 
+}
+
+/* Syntactic sugar for sldns_rr_new_frm_str_internal */
+static int
+sldns_rdf_type_maybe_quoted(sldns_rdf_type rdf_type)
+{
+       return  rdf_type == LDNS_RDF_TYPE_STR ||
+               rdf_type == LDNS_RDF_TYPE_LONG_STR;
+}
+
+/** see if rdata is quoted */
+static int
+rrinternal_get_quoted(sldns_buffer* strbuf, const char** delimiters,
+       sldns_rdf_type rdftype)
+{
+       if(sldns_rdf_type_maybe_quoted(rdftype) &&
+               sldns_buffer_remaining(strbuf) > 0) {
+
+               /* skip spaces */
+               while(sldns_buffer_remaining(strbuf) > 0 &&
+                       *(sldns_buffer_current(strbuf)) == ' ') {
+                       sldns_buffer_skip(strbuf, 1);
+               }
+
+               if(sldns_buffer_remaining(strbuf) > 0 &&
+                       *(sldns_buffer_current(strbuf)) == '\"') {
+                       *delimiters = "\"\0";
+                       sldns_buffer_skip(strbuf, 1);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/** spool hex data into rdata */
+static int
+rrinternal_spool_hex(char* token, uint8_t* rr, size_t rr_len,
+       size_t rr_cur_len, size_t* cur_hex_data_size, size_t hex_data_size)
+{
+       char* p = token;
+       while(*p) {
+               if(isspace((unsigned char)*p)) {
+                       p++;
+                       continue;
+               }
+               if(!isxdigit((unsigned char)*p))
+                       return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA,
+                               p-token);
+               if(*cur_hex_data_size >= hex_data_size)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA,
+                               p-token);
+               /* extra robust check */
+               if(rr_cur_len+(*cur_hex_data_size)/2 >= rr_len)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                               p-token);
+               /* see if 16s or 1s */
+               if( ((*cur_hex_data_size)&1) == 0) {
+                       rr[rr_cur_len+(*cur_hex_data_size)/2] =
+                               (uint8_t)sldns_hexdigit_to_int(*p)*16;
+               } else {
+                       rr[rr_cur_len+(*cur_hex_data_size)/2] +=
+                               (uint8_t)sldns_hexdigit_to_int(*p);
+               }
+               p++;
+               (*cur_hex_data_size)++;
+       }
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** read unknown rr type format */
+static int
+rrinternal_parse_unknown(sldns_buffer* strbuf, char* token, size_t token_len,
+        uint8_t* rr, size_t* rr_len, size_t* rr_cur_len, size_t pre_data_pos)
+{
+       const char* delim = "\n\t ";
+       size_t hex_data_size, cur_hex_data_size;
+       /* go back to before \#
+        * and skip it while setting delimiters better
+        */
+       sldns_buffer_set_position(strbuf, pre_data_pos);
+       if(sldns_bget_token(strbuf, token, delim, token_len) == -1)
+               return LDNS_WIREPARSE_ERR_GENERAL; /* should not fail */
+       /* read rdata octet length */
+       if(sldns_bget_token(strbuf, token, delim, token_len) == -1) {
+               /* something goes very wrong here */
+               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA,
+                       sldns_buffer_position(strbuf));
+       }
+       hex_data_size = (size_t)atoi(token);
+       if(hex_data_size > LDNS_MAX_RDFLEN || 
+               *rr_cur_len + hex_data_size > *rr_len) {
+               return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                       sldns_buffer_position(strbuf));
+       }
+       /* copy hex chars into hex str (2 chars per byte) */
+       hex_data_size *= 2;
+       cur_hex_data_size = 0;
+       while(cur_hex_data_size < hex_data_size) {
+               int status;
+               ssize_t c = sldns_bget_token(strbuf, token, delim, token_len);
+               if((status = rrinternal_spool_hex(token, rr, *rr_len,
+                       *rr_cur_len, &cur_hex_data_size, hex_data_size)) != 0)
+                       return RET_ERR_SHIFT(status,
+                               sldns_buffer_position(strbuf)-strlen(token));
+               if(c == -1) {
+                       if(cur_hex_data_size != hex_data_size)
+                               return RET_ERR(
+                                       LDNS_WIREPARSE_ERR_SYNTAX_RDATA,
+                                       sldns_buffer_position(strbuf));
+                       break;
+               }
+       }
+       *rr_cur_len += hex_data_size/2;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** parse normal RR rdata element */
+static int
+rrinternal_parse_rdf(sldns_buffer* strbuf, char* token, size_t token_len,
+       uint8_t* rr, size_t rr_len, size_t* rr_cur_len, sldns_rdf_type rdftype,
+       uint16_t rr_type, uint16_t r_cnt, uint16_t r_max, size_t dname_len,
+       uint8_t* origin, size_t origin_len)
+{
+       size_t len;
+       int status;
+
+       switch(rdftype) {
+       case LDNS_RDF_TYPE_DNAME:
+               /* check if the origin should be used or concatenated */
+               if(strcmp(token, "@") == 0) {
+                       uint8_t* tocopy;
+                       size_t copylen;
+                       if(origin) {
+                               copylen = origin_len;
+                               tocopy = origin;
+                       } else if(rr_type == LDNS_RR_TYPE_SOA) {
+                               copylen = dname_len;
+                               tocopy = rr; /* copy rr owner name */
+                       } else {
+                               copylen = 1;
+                               tocopy = (uint8_t*)"\0";
+                       }
+                       if((*rr_cur_len) + copylen > rr_len)
+                               return RET_ERR(
+                                       LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                                       sldns_buffer_position(strbuf));
+                       memmove(rr+*rr_cur_len, tocopy, copylen);
+                       (*rr_cur_len) += copylen;
+               } else {
+                       size_t dlen = rr_len - (*rr_cur_len);
+                       int s = sldns_str2wire_dname_buf_origin(token,
+                               rr+*rr_cur_len, &dlen, origin, origin_len);
+                       if(s) return RET_ERR_SHIFT(s,
+                               sldns_buffer_position(strbuf)-strlen(token));
+                       (*rr_cur_len) += dlen;
+               }
+               return LDNS_WIREPARSE_ERR_OK;
+
+       case LDNS_RDF_TYPE_HEX:
+       case LDNS_RDF_TYPE_B64:
+               /* When this is the last rdata field, then the
+                * rest should be read in (cause then these
+                * rdf types may contain spaces). */
+               if(r_cnt == r_max - 1) {
+                       size_t tlen = strlen(token);
+                       (void)sldns_bget_token(strbuf, token+tlen, "\n",
+                               token_len - tlen);
+               }
+               break;
+       default:
+               break;
+       }
+
+       len = rr_len - (*rr_cur_len);
+       if((status=sldns_str2wire_rdf_buf(token, rr+(*rr_cur_len), &len,
+               rdftype)) != 0)
+               return RET_ERR_SHIFT(status,
+                       sldns_buffer_position(strbuf)-strlen(token));
+       *rr_cur_len += len;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+/**
+ * Parse one rdf token.  Takes care of quotes and parenthesis.
+ */
+static int
+sldns_parse_rdf_token(sldns_buffer* strbuf, char* token, size_t token_len,
+       int* quoted, int* parens, size_t* pre_data_pos,
+       const char* delimiters, sldns_rdf_type rdftype, size_t* token_strlen)
+{
+       size_t slen;
+
+       /* skip spaces */
+       while(sldns_buffer_remaining(strbuf) > 0 && !*quoted &&
+               *(sldns_buffer_current(strbuf)) == ' ') {
+               sldns_buffer_skip(strbuf, 1);
+       }
+
+       *pre_data_pos = sldns_buffer_position(strbuf);
+       if(sldns_bget_token_par(strbuf, token, (*quoted)?"\"":delimiters,
+               token_len, parens, (*quoted)?NULL:" \t") == -1) {
+               return 0;
+       }
+       slen = strlen(token);
+       /* check if not quoted yet, and we have encountered quotes */
+       if(!*quoted && sldns_rdf_type_maybe_quoted(rdftype) &&
+               slen >= 2 &&
+               (token[0] == '"' || token[0] == '\'') && 
+               (token[slen-1] == '"' || token[slen-1] == '\'')) {
+               /* move token two smaller (quotes) with endnull */
+               memmove(token, token+1, slen-2);
+               token[slen-2] = 0;
+               slen -= 2;
+               *quoted = 1;
+       } else if(!*quoted && sldns_rdf_type_maybe_quoted(rdftype) &&
+               slen >= 2 &&
+               (token[0] == '"' || token[0] == '\'')) {
+               /* got the start quote (remove it) but read remainder
+                * of quoted string as well into remainder of token */
+               memmove(token, token+1, slen-1);
+               token[slen-1] = 0;
+               slen -= 1;
+               *quoted = 1;
+               /* rewind buffer over skipped whitespace */
+               while(sldns_buffer_position(strbuf) > 0 &&
+                       (sldns_buffer_current(strbuf)[-1] == ' ' ||
+                       sldns_buffer_current(strbuf)[-1] == '\t')) {
+                       sldns_buffer_skip(strbuf, -1);
+               }
+               if(sldns_bget_token_par(strbuf, token+slen,
+                       "\"", token_len-slen,
+                       parens, NULL) == -1) {
+                       return 0;
+               }
+               slen = strlen(token);
+       }
+       *token_strlen = slen;
+       return 1;
+}
+
+/** Add space and one more rdf token onto the existing token string. */
+static int
+sldns_affix_token(sldns_buffer* strbuf, char* token, size_t* token_len,
+       int* quoted, int* parens, size_t* pre_data_pos,
+       const char* delimiters, sldns_rdf_type rdftype, size_t* token_strlen)
+{
+       size_t addlen = *token_len - *token_strlen;
+       size_t addstrlen = 0;
+
+       /* add space */
+       if(addlen < 1) return 0;
+       token[*token_strlen] = ' ';
+       token[++(*token_strlen)] = 0;
+
+       /* read another token */
+       addlen = *token_len - *token_strlen;
+       if(!sldns_parse_rdf_token(strbuf, token+*token_strlen, addlen, quoted,
+               parens, pre_data_pos, delimiters, rdftype, &addstrlen))
+               return 0;
+       (*token_strlen) += addstrlen;
+       return 1;
+}
+
+/** parse rdata from string into rr buffer(-remainder after dname). */
+static int
+rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len,
+       uint8_t* rr, size_t* rr_len, size_t dname_len, uint16_t rr_type,
+       uint8_t* origin, size_t origin_len)
+{
+       const sldns_rr_descriptor *desc = sldns_rr_descript((uint16_t)rr_type);
+       uint16_t r_cnt, r_min, r_max;
+       size_t rr_cur_len = dname_len + 10, pre_data_pos, token_strlen;
+       int was_unknown_rr_format = 0, parens = 0, status, quoted;
+       const char* delimiters;
+       sldns_rdf_type rdftype;
+       /* a desc is always returned */
+       if(!desc) return LDNS_WIREPARSE_ERR_GENERAL;
+       r_max = sldns_rr_descriptor_maximum(desc);
+       r_min = sldns_rr_descriptor_minimum(desc);
+       /* robust check */
+       if(rr_cur_len > *rr_len)
+               return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                       sldns_buffer_position(strbuf));
+
+       /* because number of fields can be variable, we can't rely on
+        * _maximum() only */
+       for(r_cnt=0; r_cnt < r_max; r_cnt++) {
+               rdftype = sldns_rr_descriptor_field_type(desc, r_cnt);
+               delimiters = rrinternal_get_delims(rdftype, r_cnt, r_max);
+               quoted = rrinternal_get_quoted(strbuf, &delimiters, rdftype);
+
+               if(!sldns_parse_rdf_token(strbuf, token, token_len, &quoted,
+                       &parens, &pre_data_pos, delimiters, rdftype,
+                       &token_strlen))
+                       break;
+
+               /* rfc3597 specifies that any type can be represented
+                * with \# method, which can contain spaces...
+                * it does specify size though... */
+
+               /* unknown RR data */
+               if(token_strlen>=2 && strncmp(token, "\\#", 2) == 0 &&
+                       !quoted && (token_strlen == 2 || token[2]==' ')) {
+                       was_unknown_rr_format = 1;
+                       if((status=rrinternal_parse_unknown(strbuf, token,
+                               token_len, rr, rr_len, &rr_cur_len, 
+                               pre_data_pos)) != 0)
+                               return status;
+               } else if(token_strlen > 0 || quoted) {
+                       if(rdftype == LDNS_RDF_TYPE_HIP) {
+                               /* affix the HIT and PK fields, with a space */
+                               if(!sldns_affix_token(strbuf, token,
+                                       &token_len, &quoted, &parens,
+                                       &pre_data_pos, delimiters,
+                                       rdftype, &token_strlen))
+                                       break;
+                               if(!sldns_affix_token(strbuf, token,
+                                       &token_len, &quoted, &parens,
+                                       &pre_data_pos, delimiters,
+                                       rdftype, &token_strlen))
+                                       break;
+                       }
+
+                       /* normal RR */
+                       if((status=rrinternal_parse_rdf(strbuf, token,
+                               token_len, rr, *rr_len, &rr_cur_len, rdftype,
+                               rr_type, r_cnt, r_max, dname_len, origin,
+                               origin_len)) != 0) {
+                               return status;
+                       }
+               }
+       }
+       if(!was_unknown_rr_format && r_cnt+1 < r_min) {
+               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_MISSING_VALUE,
+                       sldns_buffer_position(strbuf));
+       }
+       while(parens != 0) {
+               /* read remainder, must be "" */
+               if(sldns_bget_token_par(strbuf, token, "\n", token_len,
+                       &parens, " \t") == -1) {
+                       if(parens != 0)
+                               return RET_ERR(LDNS_WIREPARSE_ERR_PARENTHESIS,
+                                       sldns_buffer_position(strbuf));
+                       break;
+               }
+               if(strcmp(token, "") != 0)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_PARENTHESIS,
+                               sldns_buffer_position(strbuf));
+       }
+       /* write rdata length */
+       sldns_write_uint16(rr+dname_len+8, rr_cur_len-dname_len-10);
+       *rr_len = rr_cur_len;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+/*
+ * trailing spaces are allowed
+ * leading spaces are not allowed
+ * allow ttl to be optional
+ * class is optional too
+ * if ttl is missing, and default_ttl is 0, use DEF_TTL
+ * allow ttl to be written as 1d3h
+ * So the RR should look like. e.g.
+ * miek.nl. 3600 IN MX 10 elektron.atoom.net
+ * or
+ * miek.nl. 1h IN MX 10 elektron.atoom.net
+ * or
+ * miek.nl. IN MX 10 elektron.atoom.net
+ */
+static int
+sldns_str2wire_rr_buf_internal(const char* str, uint8_t* rr, size_t* len,
+       size_t* dname_len, uint32_t default_ttl, uint8_t* origin,
+       size_t origin_len, uint8_t* prev, size_t prev_len, int question)
+{
+       int status;
+       int not_there = 0;
+       char token[LDNS_MAX_RDFLEN+1];
+       uint32_t ttl = 0;
+       uint16_t tp = 0, cl = 0;
+       size_t ddlen = 0;
+
+       /* string in buffer */
+       sldns_buffer strbuf;
+       sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str));
+       if(!dname_len) dname_len = &ddlen;
+
+       /* parse the owner */
+       if((status=rrinternal_get_owner(&strbuf, rr, len, dname_len, origin,
+               origin_len, prev, prev_len, token, sizeof(token))) != 0)
+               return status;
+
+       /* parse the [ttl] [class] <type> */
+       if((status=rrinternal_get_ttl(&strbuf, token, sizeof(token),
+               &not_there, &ttl, default_ttl)) != 0)
+               return status;
+       if((status=rrinternal_get_class(&strbuf, token, sizeof(token),
+               &not_there, &cl)) != 0)
+               return status;
+       if((status=rrinternal_get_type(&strbuf, token, sizeof(token),
+               &not_there, &tp)) != 0)
+               return status;
+       /* put ttl, class, type into the rr result */
+       if((status=rrinternal_write_typeclassttl(&strbuf, rr, *len, *dname_len, tp, cl,
+               ttl, question)) != 0)
+               return status;
+       /* for a question-RR we are done, no rdata */
+       if(question) {
+               *len = *dname_len + 4;
+               return LDNS_WIREPARSE_ERR_OK;
+       }
+
+       /* rdata */
+       if((status=rrinternal_parse_rdata(&strbuf, token, sizeof(token),
+               rr, len, *dname_len, tp, origin, origin_len)) != 0)
+               return status;
+
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_rr_buf(const char* str, uint8_t* rr, size_t* len,
+       size_t* dname_len, uint32_t default_ttl, uint8_t* origin,
+       size_t origin_len, uint8_t* prev, size_t prev_len)
+{
+       return sldns_str2wire_rr_buf_internal(str, rr, len, dname_len,
+               default_ttl, origin, origin_len, prev, prev_len, 0);
+}
+
+int sldns_str2wire_rr_question_buf(const char* str, uint8_t* rr, size_t* len,
+       size_t* dname_len, uint8_t* origin, size_t origin_len, uint8_t* prev,
+       size_t prev_len)
+{
+       return sldns_str2wire_rr_buf_internal(str, rr, len, dname_len,
+               0, origin, origin_len, prev, prev_len, 1);
+}
+
+uint16_t sldns_wirerr_get_type(uint8_t* rr, size_t len, size_t dname_len)
+{
+       if(len < dname_len+2)
+               return 0;
+       return sldns_read_uint16(rr+dname_len);
+}
+
+uint16_t sldns_wirerr_get_class(uint8_t* rr, size_t len, size_t dname_len)
+{
+       if(len < dname_len+4)
+               return 0;
+       return sldns_read_uint16(rr+dname_len+2);
+}
+
+uint32_t sldns_wirerr_get_ttl(uint8_t* rr, size_t len, size_t dname_len)
+{
+       if(len < dname_len+8)
+               return 0;
+       return sldns_read_uint32(rr+dname_len+4);
+}
+
+uint16_t sldns_wirerr_get_rdatalen(uint8_t* rr, size_t len, size_t dname_len)
+{
+       if(len < dname_len+10)
+               return 0;
+       return sldns_read_uint16(rr+dname_len+8);
+}
+
+uint8_t* sldns_wirerr_get_rdata(uint8_t* rr, size_t len, size_t dname_len)
+{
+       if(len < dname_len+10)
+               return NULL;
+       return rr+dname_len+10;
+}
+
+uint8_t* sldns_wirerr_get_rdatawl(uint8_t* rr, size_t len, size_t dname_len)
+{
+       if(len < dname_len+10)
+               return NULL;
+       return rr+dname_len+8;
+}
+
+const char* sldns_get_errorstr_parse(int e)
+{
+       sldns_lookup_table *lt;
+       lt = sldns_lookup_by_id(sldns_wireparse_errors, LDNS_WIREPARSE_ERROR(e));
+       return lt?lt->name:"unknown error";
+}
+
+/* Strip whitespace from the start and the end of <line>.  */
+static char *
+sldns_strip_ws(char *line)
+{
+        char *s = line, *e;
+
+        for (s = line; *s && isspace((unsigned char)*s); s++)
+                ;
+        for (e = strchr(s, 0); e > s+2 && isspace((unsigned char)e[-1]) && e[-2] != '\\'; e--)
+                ;
+        *e = 0;
+        return s;
+}
+
+int sldns_fp2wire_rr_buf(FILE* in, uint8_t* rr, size_t* len, size_t* dname_len,
+       struct sldns_file_parse_state* parse_state)
+{
+       char line[LDNS_RR_BUF_SIZE+1];
+       ssize_t size;
+
+       /* read an entire line in from the file */
+       if((size = sldns_fget_token_l(in, line, LDNS_PARSE_SKIP_SPACE,
+               LDNS_RR_BUF_SIZE, parse_state?&parse_state->lineno:NULL))
+               == -1) {
+               /* if last line was empty, we are now at feof, which is not
+                * always a parse error (happens when for instance last line
+                * was a comment)
+                */
+               return LDNS_WIREPARSE_ERR_SYNTAX;
+       }
+
+       /* we can have the situation, where we've read ok, but still got
+        * no bytes to play with, in this case size is 0 */
+       if(size == 0) {
+               *len = 0;
+               *dname_len = 0;
+               return LDNS_WIREPARSE_ERR_OK;
+       }
+
+       if(strncmp(line, "$ORIGIN", 7) == 0 && isspace((unsigned char)line[7])) {
+               int s;
+               *len = 0;
+               *dname_len = 0;
+               if(!parse_state) return LDNS_WIREPARSE_ERR_OK;
+               parse_state->origin_len = sizeof(parse_state->origin);
+               s = sldns_str2wire_dname_buf(sldns_strip_ws(line+8),
+                       parse_state->origin, &parse_state->origin_len);
+               if(s) parse_state->origin_len = 0;
+               return s;
+       } else if(strncmp(line, "$TTL", 4) == 0 && isspace((unsigned char)line[4])) {
+               const char* end = NULL;
+               *len = 0;
+               *dname_len = 0;
+               if(!parse_state) return LDNS_WIREPARSE_ERR_OK;
+               parse_state->default_ttl = sldns_str2period(
+                       sldns_strip_ws(line+5), &end);
+       } else if (strncmp(line, "$INCLUDE", 8) == 0) {
+               *len = 0;
+               *dname_len = 0;
+               return LDNS_WIREPARSE_ERR_INCLUDE;
+       } else {
+               return sldns_str2wire_rr_buf(line, rr, len, dname_len,
+                       parse_state?parse_state->default_ttl:0,
+                       (parse_state&&parse_state->origin_len)?
+                               parse_state->origin:NULL,
+                       parse_state->origin_len,
+                       (parse_state&&parse_state->prev_rr_len)?
+                               parse_state->prev_rr:NULL,
+                       parse_state->prev_rr_len);
+       }
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_rdf_buf(const char* str, uint8_t* rd, size_t* len,
+       sldns_rdf_type rdftype)
+{
+       switch (rdftype) {
+       case LDNS_RDF_TYPE_DNAME:
+               return sldns_str2wire_dname_buf(str, rd, len);
+       case LDNS_RDF_TYPE_INT8:
+               return sldns_str2wire_int8_buf(str, rd, len);
+       case LDNS_RDF_TYPE_INT16:
+               return sldns_str2wire_int16_buf(str, rd, len);
+       case LDNS_RDF_TYPE_INT32:
+               return sldns_str2wire_int32_buf(str, rd, len);
+       case LDNS_RDF_TYPE_A:
+               return sldns_str2wire_a_buf(str, rd, len);
+       case LDNS_RDF_TYPE_AAAA:
+               return sldns_str2wire_aaaa_buf(str, rd, len);
+       case LDNS_RDF_TYPE_STR:
+               return sldns_str2wire_str_buf(str, rd, len);
+       case LDNS_RDF_TYPE_APL:
+               return sldns_str2wire_apl_buf(str, rd, len);
+       case LDNS_RDF_TYPE_B64:
+               return sldns_str2wire_b64_buf(str, rd, len);
+       case LDNS_RDF_TYPE_B32_EXT:
+               return sldns_str2wire_b32_ext_buf(str, rd, len);
+       case LDNS_RDF_TYPE_HEX:
+               return sldns_str2wire_hex_buf(str, rd, len);
+       case LDNS_RDF_TYPE_NSEC:
+               return sldns_str2wire_nsec_buf(str, rd, len);
+       case LDNS_RDF_TYPE_TYPE:
+               return sldns_str2wire_type_buf(str, rd, len);
+       case LDNS_RDF_TYPE_CLASS:
+               return sldns_str2wire_class_buf(str, rd, len);
+       case LDNS_RDF_TYPE_CERT_ALG:
+               return sldns_str2wire_cert_alg_buf(str, rd, len);
+       case LDNS_RDF_TYPE_ALG:
+               return sldns_str2wire_alg_buf(str, rd, len);
+       case LDNS_RDF_TYPE_TIME:
+               return sldns_str2wire_time_buf(str, rd, len);
+       case LDNS_RDF_TYPE_PERIOD:
+               return sldns_str2wire_period_buf(str, rd, len);
+       case LDNS_RDF_TYPE_LOC:
+               return sldns_str2wire_loc_buf(str, rd, len);
+       case LDNS_RDF_TYPE_WKS:
+               return sldns_str2wire_wks_buf(str, rd, len);
+       case LDNS_RDF_TYPE_NSAP:
+               return sldns_str2wire_nsap_buf(str, rd, len);
+       case LDNS_RDF_TYPE_ATMA:
+               return sldns_str2wire_atma_buf(str, rd, len);
+       case LDNS_RDF_TYPE_IPSECKEY:
+               return sldns_str2wire_ipseckey_buf(str, rd, len);
+       case LDNS_RDF_TYPE_NSEC3_SALT:
+               return sldns_str2wire_nsec3_salt_buf(str, rd, len);
+       case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
+               return sldns_str2wire_b32_ext_buf(str, rd, len);
+       case LDNS_RDF_TYPE_ILNP64:
+               return sldns_str2wire_ilnp64_buf(str, rd, len);
+       case LDNS_RDF_TYPE_EUI48:
+               return sldns_str2wire_eui48_buf(str, rd, len);
+       case LDNS_RDF_TYPE_EUI64:
+               return sldns_str2wire_eui64_buf(str, rd, len);
+       case LDNS_RDF_TYPE_TAG:
+               return sldns_str2wire_tag_buf(str, rd, len);
+       case LDNS_RDF_TYPE_LONG_STR:
+               return sldns_str2wire_long_str_buf(str, rd, len);
+       case LDNS_RDF_TYPE_HIP:
+               return sldns_str2wire_hip_buf(str, rd, len);
+       case LDNS_RDF_TYPE_INT16_DATA:
+               return sldns_str2wire_int16_data_buf(str, rd, len);
+       case LDNS_RDF_TYPE_UNKNOWN:
+       case LDNS_RDF_TYPE_SERVICE:
+               return LDNS_WIREPARSE_ERR_NOT_IMPL;
+       case LDNS_RDF_TYPE_NONE:
+       default:
+               break;
+       }
+       return LDNS_WIREPARSE_ERR_GENERAL;
+}
+
+int sldns_str2wire_int8_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       char* end;
+       uint8_t r = (uint8_t)strtol((char*)str, &end, 10);
+       if(*end != 0)
+               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str);
+       if(*len < 1)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       rd[0] = r;
+       *len = 1;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_int16_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       char* end;
+       uint16_t r = (uint16_t)strtol((char*)str, &end, 10);
+       if(*end != 0)
+               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str);
+       if(*len < 2)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       sldns_write_uint16(rd, r);
+       *len = 2;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_int32_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       char* end;
+       uint32_t r;
+       errno = 0; /* must set to zero before call,
+                       note race condition on errno */
+       if(*str == '-')
+               r = (uint32_t)strtol((char*)str, &end, 10);
+       else    r = (uint32_t)strtoul((char*)str, &end, 10);
+       if(*end != 0)
+               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str);
+       if(errno == ERANGE)
+               return LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW;
+       if(*len < 4)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       sldns_write_uint32(rd, r);
+       *len = 4;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_a_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       struct in_addr address;
+       if(inet_pton(AF_INET, (char*)str, &address) != 1)
+               return LDNS_WIREPARSE_ERR_SYNTAX_IP4;
+       if(*len < sizeof(address))
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       memmove(rd, &address, sizeof(address));
+       *len = sizeof(address);
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_aaaa_buf(const char* str, uint8_t* rd, size_t* len)
+{
+#ifdef AF_INET6
+       uint8_t address[LDNS_IP6ADDRLEN + 1];
+       if(inet_pton(AF_INET6, (char*)str, address) != 1)
+               return LDNS_WIREPARSE_ERR_SYNTAX_IP6;
+       if(*len < LDNS_IP6ADDRLEN)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       memmove(rd, address, LDNS_IP6ADDRLEN);
+       *len = LDNS_IP6ADDRLEN;
+       return LDNS_WIREPARSE_ERR_OK;
+#else
+       return LDNS_WIREPARSE_ERR_NOT_IMPL;
+#endif
+}
+
+int sldns_str2wire_str_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       uint8_t ch = 0;
+       size_t sl = 0;
+       const char* s = str;
+       /* skip length byte */
+       if(*len < 1)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+
+       /* read characters */
+       while(sldns_parse_char(&ch, &s)) {
+               if(sl >= 255)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, s-str);
+               if(*len < sl+1)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                               s-str);
+               rd[++sl] = ch;
+       }
+       if(!s)
+               return LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE;
+       rd[0] = (uint8_t)sl;
+       *len = sl+1;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_apl_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       const char *my_str = str;
+
+       char my_ip_str[64];
+       size_t ip_str_len;
+
+       uint16_t family;
+       int negation;
+       size_t adflength = 0;
+       uint8_t data[16+4];
+       uint8_t prefix;
+       size_t i;
+
+       if(strlen(my_str) == 0) {
+               /* empty APL element, no data, no string */
+               *len = 0;
+               return LDNS_WIREPARSE_ERR_OK;
+       }
+
+       /* [!]afi:address/prefix */
+       if (strlen(my_str) < 2
+                       || strchr(my_str, ':') == NULL
+                       || strchr(my_str, '/') == NULL
+                       || strchr(my_str, ':') > strchr(my_str, '/')) {
+               return LDNS_WIREPARSE_ERR_INVALID_STR;
+       }
+
+       if (my_str[0] == '!') {
+               negation = 1;
+               my_str += 1;
+       } else {
+               negation = 0;
+       }
+
+       family = (uint16_t) atoi(my_str);
+
+       my_str = strchr(my_str, ':') + 1;
+
+       /* need ip addr and only ip addr for inet_pton */
+       ip_str_len = (size_t) (strchr(my_str, '/') - my_str);
+       if(ip_str_len+1 > sizeof(my_ip_str))
+               return LDNS_WIREPARSE_ERR_INVALID_STR;
+       (void)strlcpy(my_ip_str, my_str, sizeof(my_ip_str));
+       my_ip_str[ip_str_len] = 0;
+
+       if (family == 1) {
+               /* ipv4 */
+               if(inet_pton(AF_INET, my_ip_str, data+4) == 0)
+                       return LDNS_WIREPARSE_ERR_INVALID_STR;
+               for (i = 0; i < 4; i++) {
+                       if (data[i+4] != 0) {
+                               adflength = i + 1;
+                       }
+               }
+       } else if (family == 2) {
+               /* ipv6 */
+               if (inet_pton(AF_INET6, my_ip_str, data+4) == 0)
+                       return LDNS_WIREPARSE_ERR_INVALID_STR;
+               for (i = 0; i < 16; i++) {
+                       if (data[i+4] != 0) {
+                               adflength = i + 1;
+                       }
+               }
+       } else {
+               /* unknown family */
+               return LDNS_WIREPARSE_ERR_INVALID_STR;
+       }
+
+       my_str = strchr(my_str, '/') + 1;
+       prefix = (uint8_t) atoi(my_str);
+
+       sldns_write_uint16(data, family);
+       data[2] = prefix;
+       data[3] = (uint8_t)adflength;
+       if (negation) {
+               /* set bit 1 of byte 3 */
+               data[3] = data[3] | 0x80;
+       }
+
+       if(*len < 4+adflength)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       memmove(rd, data, 4+adflength);
+       *len = 4+adflength;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_b64_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       size_t sz = sldns_b64_pton_calculate_size(strlen(str));
+       int n;
+       if(*len < sz)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       n = sldns_b64_pton(str, rd, *len);
+       if(n < 0)
+               return LDNS_WIREPARSE_ERR_SYNTAX_B64;
+       *len = (size_t)n;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_b32_ext_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       size_t slen = strlen(str);
+       size_t sz = sldns_b32_pton_calculate_size(slen);
+       int n;
+       if(*len < 1+sz)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       rd[0] = (uint8_t)sz;
+       n = sldns_b32_pton_extended_hex(str, slen, rd+1, *len-1);
+       if(n < 0)
+               return LDNS_WIREPARSE_ERR_SYNTAX_B32_EXT;
+       *len = (size_t)n+1;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_hex_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       const char* s = str;
+       size_t dlen = 0; /* number of hexdigits parsed */
+       while(*s) {
+               if(isspace((unsigned char)*s)) {
+                       s++;
+                       continue;
+               }
+               if(!isxdigit((unsigned char)*s))
+                       return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
+               if(*len < dlen/2 + 1)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                               s-str);
+               if((dlen&1)==0)
+                       rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16;
+               else    rd[dlen/2] += (uint8_t)sldns_hexdigit_to_int(*s++);
+               dlen++;
+       }
+       if((dlen&1)!=0)
+               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
+       *len = dlen/2;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_nsec_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       const char *delim = "\n\t ";
+       char token[64]; /* for a type name */
+       size_t type_count = 0;
+       int block;
+       size_t used = 0;
+       uint16_t maxtype = 0;
+       uint8_t typebits[8192]; /* 65536 bits */
+       uint8_t window_in_use[256];
+
+       /* string in buffer */
+       sldns_buffer strbuf;
+       sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str));
+
+       /* parse the types */
+       memset(typebits, 0, sizeof(typebits));
+       memset(window_in_use, 0, sizeof(window_in_use));
+       while(sldns_buffer_remaining(&strbuf) > 0 &&
+               sldns_bget_token(&strbuf, token, delim, sizeof(token)) != -1) {
+               uint16_t t = sldns_get_rr_type_by_name(token);
+               if(token[0] == 0)
+                       continue;
+               if(t == 0 && strcmp(token, "TYPE0") != 0)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE,
+                               sldns_buffer_position(&strbuf));
+               typebits[t/8] |= (0x80>>(t%8));
+               window_in_use[t/256] = 1;
+               type_count++;
+               if(t > maxtype) maxtype = t;
+       }
+
+       /* empty NSEC bitmap */
+       if(type_count == 0) {
+               *len = 0;
+               return LDNS_WIREPARSE_ERR_OK;
+       }
+
+       /* encode windows {u8 windowblock, u8 bitmaplength, 0-32u8 bitmap},
+        * block is 0-255 upper octet of types, length if 0-32. */
+       for(block = 0; block <= (int)maxtype/256; block++) {
+               int i, blocklen = 0;
+               if(!window_in_use[block])
+                       continue;
+               for(i=0; i<32; i++) {
+                       if(typebits[block*32+i] != 0)
+                               blocklen = i+1;
+               }
+               if(blocklen == 0)
+                       continue; /* empty window should have been !in_use */
+               if(used+blocklen+2 > *len)
+                       return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+               rd[used+0] = (uint8_t)block;
+               rd[used+1] = (uint8_t)blocklen;
+               for(i=0; i<blocklen; i++) {
+                       rd[used+2+i] = typebits[block*32+i];
+               }
+               used += blocklen+2;
+       }
+       *len = used;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_type_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       uint16_t t = sldns_get_rr_type_by_name(str);
+       if(t == 0 && strcmp(str, "TYPE0") != 0)
+               return LDNS_WIREPARSE_ERR_SYNTAX_TYPE;
+       if(*len < 2)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       sldns_write_uint16(rd, t);
+       *len = 2;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_class_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       uint16_t c = sldns_get_rr_class_by_name(str);
+       if(c == 0 && strcmp(str, "CLASS0") != 0)
+               return LDNS_WIREPARSE_ERR_SYNTAX_CLASS;
+       if(*len < 2)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       sldns_write_uint16(rd, c);
+       *len = 2;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+/* An certificate alg field can either be specified as a 8 bits number
+ * or by its symbolic name. Handle both */
+int sldns_str2wire_cert_alg_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       sldns_lookup_table *lt = sldns_lookup_by_name(sldns_cert_algorithms,
+               str);
+       if(*len < 2)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       if(lt) {
+               sldns_write_uint16(rd, (uint16_t)lt->id);
+       } else {
+               int s = sldns_str2wire_int16_buf(str, rd, len);
+               if(s) return s;
+               if(sldns_read_uint16(rd) == 0)
+                       return LDNS_WIREPARSE_ERR_CERT_BAD_ALGORITHM;
+       }
+       *len = 2;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+/* An alg field can either be specified as a 8 bits number
+ * or by its symbolic name. Handle both */
+int sldns_str2wire_alg_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       sldns_lookup_table *lt = sldns_lookup_by_name(sldns_algorithms, str);
+       if(*len < 1)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       if(lt) {
+               rd[0] = (uint8_t)lt->id;
+               *len = 1;
+       } else {
+               /* try as-is (a number) */
+               return sldns_str2wire_int8_buf(str, rd, len);
+       }
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_time_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       /* convert a time YYYYDDMMHHMMSS to wireformat */
+       struct tm tm;
+       if(*len < 4)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+
+       /* Try to scan the time... */
+       memset(&tm, 0, sizeof(tm));
+       if (strlen(str) == 14 && sscanf(str, "%4d%2d%2d%2d%2d%2d",
+               &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour,
+               &tm.tm_min, &tm.tm_sec) == 6) {
+               tm.tm_year -= 1900;
+               tm.tm_mon--;
+               /* Check values */
+               if (tm.tm_year < 70)
+                       return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
+               if (tm.tm_mon < 0 || tm.tm_mon > 11)
+                       return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
+               if (tm.tm_mday < 1 || tm.tm_mday > 31)
+                       return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
+               if (tm.tm_hour < 0 || tm.tm_hour > 23)
+                       return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
+               if (tm.tm_min < 0 || tm.tm_min > 59)
+                       return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
+               if (tm.tm_sec < 0 || tm.tm_sec > 59)
+                       return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
+
+               sldns_write_uint32(rd, sldns_mktime_from_utc(&tm));
+       } else {
+               /* handle it as 32 bits timestamp */
+               char *end;
+               uint32_t l = (uint32_t)strtol((char*)str, &end, 10);
+               if(*end != 0)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TIME,
+                               end-(char*)str);
+               sldns_write_uint32(rd, l);
+       }
+       *len = 4;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_period_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       const char* end;
+       uint32_t p = sldns_str2period(str, &end);
+       if(*end != 0)
+               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_PERIOD, end-str);
+       if(*len < 4)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       sldns_write_uint32(rd, p);
+       *len = 4;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** read "<digits>[.<digits>][mM]" into mantissa exponent format for LOC type */
+static int
+loc_parse_cm(char* my_str, char** endstr, uint8_t* m, uint8_t* e)
+{
+       uint32_t meters = 0, cm = 0, val;
+       while (isblank((unsigned char)*my_str)) {
+               my_str++;
+       }
+       meters = (uint32_t)strtol(my_str, &my_str, 10);
+       if (*my_str == '.') {
+               my_str++;
+               cm = (uint32_t)strtol(my_str, &my_str, 10);
+       }
+       if (meters >= 1) {
+               *e = 2;
+               val = meters;
+       } else  {
+               *e = 0;
+               val = cm;
+       }
+       while(val >= 10) {
+               (*e)++;
+               val /= 10;
+       }
+       *m = (uint8_t)val;
+
+       if (*e > 9)
+               return 0;
+       if (*my_str == 'm' || *my_str == 'M') {
+               my_str++;
+       }
+       *endstr = my_str;
+       return 1;
+}
+
+int sldns_str2wire_loc_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       uint32_t latitude = 0;
+       uint32_t longitude = 0;
+       uint32_t altitude = 0;
+
+       uint32_t equator = (uint32_t)1<<31; /* 2**31 */
+
+       /* only support version 0 */
+       uint32_t h = 0;
+       uint32_t m = 0;
+       uint8_t size_b = 1, size_e = 2;
+       uint8_t horiz_pre_b = 1, horiz_pre_e = 6;
+       uint8_t vert_pre_b = 1, vert_pre_e = 3;
+
+       double s = 0.0;
+       int northerness;
+       int easterness;
+
+       char *my_str = (char *) str;
+
+       if (isdigit((unsigned char) *my_str)) {
+               h = (uint32_t) strtol(my_str, &my_str, 10);
+       } else {
+               return LDNS_WIREPARSE_ERR_INVALID_STR;
+       }
+
+       while (isblank((unsigned char) *my_str)) {
+               my_str++;
+       }
+
+       if (isdigit((unsigned char) *my_str)) {
+               m = (uint32_t) strtol(my_str, &my_str, 10);
+       } else if (*my_str == 'N' || *my_str == 'S') {
+               goto north;
+       } else {
+               return LDNS_WIREPARSE_ERR_INVALID_STR;
+       }
+
+       while (isblank((unsigned char) *my_str)) {
+               my_str++;
+       }
+
+       if (isdigit((unsigned char) *my_str)) {
+               s = strtod(my_str, &my_str);
+       }
+
+       /* skip blanks before norterness */
+       while (isblank((unsigned char) *my_str)) {
+               my_str++;
+       }
+
+north:
+       if (*my_str == 'N') {
+               northerness = 1;
+       } else if (*my_str == 'S') {
+               northerness = 0;
+       } else {
+               return LDNS_WIREPARSE_ERR_INVALID_STR;
+       }
+
+       my_str++;
+
+       /* store number */
+       s = 1000.0 * s;
+       /* add a little to make floor in conversion a round */
+       s += 0.0005;
+       latitude = (uint32_t) s;
+       latitude += 1000 * 60 * m;
+       latitude += 1000 * 60 * 60 * h;
+       if (northerness) {
+               latitude = equator + latitude;
+       } else {
+               latitude = equator - latitude;
+       }
+       while (isblank((unsigned char)*my_str)) {
+               my_str++;
+       }
+
+       if (isdigit((unsigned char) *my_str)) {
+               h = (uint32_t) strtol(my_str, &my_str, 10);
+       } else {
+               return LDNS_WIREPARSE_ERR_INVALID_STR;
+       }
+
+       while (isblank((unsigned char) *my_str)) {
+               my_str++;
+       }
+
+       if (isdigit((unsigned char) *my_str)) {
+               m = (uint32_t) strtol(my_str, &my_str, 10);
+       } else if (*my_str == 'E' || *my_str == 'W') {
+               goto east;
+       } else {
+               return LDNS_WIREPARSE_ERR_INVALID_STR;
+       }
+
+       while (isblank((unsigned char)*my_str)) {
+               my_str++;
+       }
+
+       if (isdigit((unsigned char) *my_str)) {
+               s = strtod(my_str, &my_str);
+       }
+
+       /* skip blanks before easterness */
+       while (isblank((unsigned char)*my_str)) {
+               my_str++;
+       }
+
+east:
+       if (*my_str == 'E') {
+               easterness = 1;
+       } else if (*my_str == 'W') {
+               easterness = 0;
+       } else {
+               return LDNS_WIREPARSE_ERR_INVALID_STR;
+       }
+
+       my_str++;
+
+       /* store number */
+       s *= 1000.0;
+       /* add a little to make floor in conversion a round */
+       s += 0.0005;
+       longitude = (uint32_t) s;
+       longitude += 1000 * 60 * m;
+       longitude += 1000 * 60 * 60 * h;
+
+       if (easterness) {
+               longitude += equator;
+       } else {
+               longitude = equator - longitude;
+       }
+
+       altitude = (uint32_t)(strtod(my_str, &my_str)*100.0 +
+               10000000.0 + 0.5);
+       if (*my_str == 'm' || *my_str == 'M') {
+               my_str++;
+       }
+
+       if (strlen(my_str) > 0) {
+               if(!loc_parse_cm(my_str, &my_str, &size_b, &size_e))
+                       return LDNS_WIREPARSE_ERR_INVALID_STR;
+       }
+
+       if (strlen(my_str) > 0) {
+               if(!loc_parse_cm(my_str, &my_str, &horiz_pre_b, &horiz_pre_e))
+                       return LDNS_WIREPARSE_ERR_INVALID_STR;
+       }
+
+       if (strlen(my_str) > 0) {
+               if(!loc_parse_cm(my_str, &my_str, &vert_pre_b, &vert_pre_e))
+                       return LDNS_WIREPARSE_ERR_INVALID_STR;
+       }
+
+       if(*len < 16)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       rd[0] = 0;
+       rd[1] = ((size_b << 4) & 0xf0) | (size_e & 0x0f);
+       rd[2] = ((horiz_pre_b << 4) & 0xf0) | (horiz_pre_e & 0x0f);
+       rd[3] = ((vert_pre_b << 4) & 0xf0) | (vert_pre_e & 0x0f);
+       sldns_write_uint32(rd + 4, latitude);
+       sldns_write_uint32(rd + 8, longitude);
+       sldns_write_uint32(rd + 12, altitude);
+       *len = 16;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+static void
+ldns_tolower_str(char* s)
+{
+       if(s) {
+               while(*s) {
+                       *s = (char)tolower((unsigned char)*s);
+                       s++;
+               }
+       }
+}
+
+int sldns_str2wire_wks_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       int rd_len = 1;
+       int have_proto = 0;
+       char token[50], proto_str[50];
+       sldns_buffer strbuf;
+       sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str));
+       proto_str[0]=0;
+
+       /* check we have one byte for proto */
+       if(*len < 1)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+
+       while(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) > 0) {
+               ldns_tolower_str(token);
+               if(!have_proto) {
+                       struct protoent *p = getprotobyname(token);
+                       have_proto = 1;
+                       if(p) rd[0] = (uint8_t)p->p_proto;
+                       else rd[0] = (uint8_t)atoi(token);
+                       (void)strlcpy(proto_str, token, sizeof(proto_str));
+               } else {
+                       int serv_port;
+                       struct servent *serv = getservbyname(token, proto_str);
+                       if(serv) serv_port=(int)ntohs((uint16_t)serv->s_port);
+                       else {
+                               serv_port = atoi(token);
+                               if(serv_port == 0 && strcmp(token, "0") != 0) {
+#ifdef HAVE_ENDSERVENT
+                                       endservent();
+#endif
+#ifdef HAVE_ENDPROTOENT
+                                       endprotoent();
+#endif
+                                       return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX,
+                                               sldns_buffer_position(&strbuf));
+                               }
+                               if(serv_port < 0 || serv_port > 65535) {
+#ifdef HAVE_ENDSERVENT
+                                       endservent();
+#endif
+#ifdef HAVE_ENDPROTOENT
+                                       endprotoent();
+#endif
+                                       return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX,
+                                               sldns_buffer_position(&strbuf));
+                               }
+                       }
+                       if(rd_len < 1+serv_port/8+1) {
+                               /* bitmap is larger, init new bytes at 0 */
+                               if(*len < 1+(size_t)serv_port/8+1) {
+#ifdef HAVE_ENDSERVENT
+                                       endservent();
+#endif
+#ifdef HAVE_ENDPROTOENT
+                                       endprotoent();
+#endif
+                                       return RET_ERR(
+                                       LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                                       sldns_buffer_position(&strbuf));
+                               }
+                               memset(rd+rd_len, 0, 1+(size_t)serv_port/8+1-rd_len);
+                               rd_len = 1+serv_port/8+1;
+                       }
+                       rd[1+ serv_port/8] |= (1 << (7 - serv_port % 8));
+               }
+       }
+       *len = (size_t)rd_len;
+
+#ifdef HAVE_ENDSERVENT
+       endservent();
+#endif
+#ifdef HAVE_ENDPROTOENT
+       endprotoent();
+#endif
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_nsap_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       const char* s = str;
+       size_t slen;
+       size_t dlen = 0; /* number of hexdigits parsed */
+
+       /* just a hex string with optional dots? */
+       if (s[0] != '0' || s[1] != 'x')
+               return LDNS_WIREPARSE_ERR_INVALID_STR;
+       s += 2;
+       slen = strlen(s);
+       if(slen > LDNS_MAX_RDFLEN*2)
+               return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW;
+       while(*s) {
+               if(isspace((unsigned char)*s) || *s == '.') {
+                       s++;
+                       continue;
+               }
+               if(!isxdigit((unsigned char)*s))
+                       return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
+               if(*len < dlen/2 + 1)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                               s-str);
+               if((dlen&1)==0)
+                       rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16;
+               else    rd[dlen/2] += sldns_hexdigit_to_int(*s++);
+               dlen++;
+       }
+       if((dlen&1)!=0)
+               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
+       *len = dlen/2;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_atma_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       const char* s = str;
+       size_t slen = strlen(str);
+       size_t dlen = 0; /* number of hexdigits parsed */
+
+       /* just a hex string with optional dots? */
+       /* notimpl e.164 format */
+       if(slen > LDNS_MAX_RDFLEN*2)
+               return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW;
+       while(*s) {
+               if(isspace((unsigned char)*s) || *s == '.') {
+                       s++;
+                       continue;
+               }
+               if(!isxdigit((unsigned char)*s))
+                       return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
+               if(*len < dlen/2 + 1)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                               s-str);
+               if((dlen&1)==0)
+                       rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16;
+               else    rd[dlen/2] += sldns_hexdigit_to_int(*s++);
+               dlen++;
+       }
+       if((dlen&1)!=0)
+               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
+       *len = dlen/2;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_ipseckey_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       size_t gwlen = 0, keylen = 0;
+       int s;
+       uint8_t gwtype;
+       char token[512];
+       sldns_buffer strbuf;
+       sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str));
+
+       if(*len < 3)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       /* precedence */
+       if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0)
+               return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
+                       sldns_buffer_position(&strbuf));
+       rd[0] = (uint8_t)atoi(token);
+       /* gateway_type */
+       if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0)
+               return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
+                       sldns_buffer_position(&strbuf));
+       rd[1] = (uint8_t)atoi(token);
+       gwtype = rd[1];
+       /* algorithm */
+       if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0)
+               return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
+                       sldns_buffer_position(&strbuf));
+       rd[2] = (uint8_t)atoi(token);
+
+       /* gateway */
+       if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0)
+               return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
+                       sldns_buffer_position(&strbuf));
+       if(gwtype == 0) {
+               /* NOGATEWAY */
+               if(strcmp(token, ".") != 0)
+                       return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
+                               sldns_buffer_position(&strbuf));
+               gwlen = 0;
+       } else if(gwtype == 1) {
+               /* IP4 */
+               gwlen = *len - 3;
+               s = sldns_str2wire_a_buf(token, rd+3, &gwlen);
+               if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf));
+       } else if(gwtype == 2) {
+               /* IP6 */
+               gwlen = *len - 3;
+               s = sldns_str2wire_aaaa_buf(token, rd+3, &gwlen);
+               if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf));
+       } else if(gwtype == 3) {
+               /* DNAME */
+               gwlen = *len - 3;
+               s = sldns_str2wire_dname_buf(token, rd+3, &gwlen);
+               if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf));
+       } else {
+               /* unknown gateway type */
+               return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
+                       sldns_buffer_position(&strbuf));
+       }
+       /* double check for size */
+       if(*len < 3 + gwlen)
+               return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+                       sldns_buffer_position(&strbuf));
+
+       /* publickey in remainder of strbuf */
+       keylen = *len - 3 - gwlen;
+       s = sldns_str2wire_b64_buf((const char*)sldns_buffer_current(&strbuf),
+               rd+3+gwlen, &keylen);
+       if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf));
+
+       *len = 3 + gwlen + keylen;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_nsec3_salt_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       int i, salt_length_str = (int)strlen(str);
+       if (salt_length_str == 1 && str[0] == '-') {
+               salt_length_str = 0;
+       } else if (salt_length_str % 2 != 0) {
+               return LDNS_WIREPARSE_ERR_SYNTAX_HEX;
+       }
+       if (salt_length_str > 512)
+               return LDNS_WIREPARSE_ERR_SYNTAX_HEX;
+       if(*len < 1+(size_t)salt_length_str / 2)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       rd[0] = (uint8_t) (salt_length_str / 2);
+       for (i = 0; i < salt_length_str; i += 2) {
+               if (isxdigit((unsigned char)str[i]) &&
+                       isxdigit((unsigned char)str[i+1])) {
+                       rd[1+i/2] = (uint8_t)(sldns_hexdigit_to_int(str[i])*16
+                               + sldns_hexdigit_to_int(str[i+1]));
+               } else {
+                       return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, i);
+               }
+       }
+       *len = 1 + (size_t)rd[0];
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_ilnp64_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       unsigned int a, b, c, d;
+       uint16_t shorts[4];
+       int l;
+       if(*len < sizeof(shorts))
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+
+       if (sscanf(str, "%4x:%4x:%4x:%4x%n", &a, &b, &c, &d, &l) != 4 ||
+                       l != (int)strlen(str) || /* more data to read */
+                       strpbrk(str, "+-")       /* signed hexes */
+                       )
+               return LDNS_WIREPARSE_ERR_SYNTAX_ILNP64;
+       shorts[0] = htons(a);
+       shorts[1] = htons(b);
+       shorts[2] = htons(c);
+       shorts[3] = htons(d);
+       memmove(rd, &shorts, sizeof(shorts));
+       *len = sizeof(shorts);
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_eui48_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       unsigned int a, b, c, d, e, f;
+       int l;
+
+       if(*len < 6)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x%n",
+                       &a, &b, &c, &d, &e, &f, &l) != 6 ||
+                       l != (int)strlen(str))
+               return LDNS_WIREPARSE_ERR_SYNTAX_EUI48;
+       rd[0] = a;
+       rd[1] = b;
+       rd[2] = c;
+       rd[3] = d;
+       rd[4] = e;
+       rd[5] = f;
+       *len = 6;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_eui64_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       unsigned int a, b, c, d, e, f, g, h;
+       int l;
+
+       if(*len < 8)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x-%2x-%2x%n",
+                       &a, &b, &c, &d, &e, &f, &g, &h, &l) != 8 ||
+                       l != (int)strlen(str))
+               return LDNS_WIREPARSE_ERR_SYNTAX_EUI64;
+       rd[0] = a;
+       rd[1] = b;
+       rd[2] = c;
+       rd[3] = d;
+       rd[4] = e;
+       rd[5] = f;
+       rd[6] = g;
+       rd[7] = h;
+       *len = 8;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_tag_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       size_t slen = strlen(str);
+       const char* ptr;
+
+       if (slen > 255)
+               return LDNS_WIREPARSE_ERR_SYNTAX_TAG;
+       if(*len < slen+1)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       for (ptr = str; *ptr; ptr++) {
+               if(!isalnum((unsigned char)*ptr))
+                       return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TAG, ptr-str);
+       }
+       rd[0] = slen;
+       memmove(rd+1, str, slen);
+       *len = slen+1;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_long_str_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       uint8_t ch = 0;
+       const char* pstr = str;
+       size_t length = 0;
+
+       /* Fill data with parsed bytes */
+       while (sldns_parse_char(&ch, &pstr)) {
+               if(*len < length+1)
+                       return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+               rd[length++] = ch;
+       }
+       if(!pstr)
+               return LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE;
+       *len = length;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_hip_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       char* s, *end;
+       int e;
+       size_t hitlen, pklen = 0;
+       /* presentation format:
+        *      pk-algo HIThex pubkeybase64
+        * wireformat:
+        *      hitlen[1byte] pkalgo[1byte] pubkeylen[2byte] [hit] [pubkey] */
+       if(*len < 4)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+
+       /* read PK algorithm */
+       rd[1] = (uint8_t)strtol((char*)str, &s, 10);
+       if(*s != ' ')
+               return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, s-(char*)str);
+       s++;
+       while(*s == ' ')
+               s++;
+
+       /* read HIT hex tag */
+       /* zero terminate the tag (replace later) */
+       end = strchr(s, ' ');
+       if(!end) return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, s-(char*)str);
+       *end = 0;
+       hitlen = *len - 4;
+       if((e = sldns_str2wire_hex_buf(s, rd+4, &hitlen)) != 0) {
+               *end = ' ';
+               return RET_ERR_SHIFT(e, s-(char*)str);
+       }
+       if(hitlen > 255) {
+               *end = ' ';
+               return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, s-(char*)str+255*2);
+       }
+       rd[0] = (uint8_t)hitlen;
+       *end = ' ';
+       s = end+1;
+
+       /* read pubkey base64 sequence */
+       pklen = *len - 4 - hitlen;
+       if((e = sldns_str2wire_b64_buf(s, rd+4+hitlen, &pklen)) != 0)
+               return RET_ERR_SHIFT(e, s-(char*)str);
+       if(pklen > 65535)
+               return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, s-(char*)str+65535);
+       sldns_write_uint16(rd+2, pklen);
+
+       *len = 4 + hitlen + pklen;
+       return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_int16_data_buf(const char* str, uint8_t* rd, size_t* len)
+{
+       size_t sz = sldns_b64_pton_calculate_size(strlen(str));
+       int n;
+       if(*len < sz+2)
+               return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+       if(sz > 65535)
+               return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW;
+       n = sldns_b64_pton(str, rd+2, (*len)-2);
+       if(n < 0)
+               return LDNS_WIREPARSE_ERR_SYNTAX_B64;
+       sldns_write_uint16(rd, (uint16_t)n);
+       *len = (size_t)n;
+       return LDNS_WIREPARSE_ERR_OK;
+}
diff --git a/sldns/str2wire.h b/sldns/str2wire.h
new file mode 100644 (file)
index 0000000..527074a
--- /dev/null
@@ -0,0 +1,541 @@
+/**
+ * str2wire.h -  read txt presentation of RRs
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Parses text to wireformat.
+ */
+
+#ifndef LDNS_STR2WIRE_H
+#define LDNS_STR2WIRE_H
+
+/* include rrdef for MAX_DOMAINLEN constant */
+#include <sldns/rrdef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct sldns_struct_lookup_table;
+
+/** buffer to read an RR, cannot be larger than 64K because of packet size */
+#define LDNS_RR_BUF_SIZE 65535 /* bytes */
+#define LDNS_DEFAULT_TTL       3600
+
+/*
+ * To convert class and type to string see
+ * sldns_get_rr_class_by_name(str)
+ * sldns_get_rr_type_by_name(str)
+ * from rrdef.h
+ */
+
+/**
+ * Convert text string into dname wireformat, mallocless, with user buffer.
+ * @param str: the text string with the domain name.
+ * @param buf: the result buffer, suggested size LDNS_MAX_DOMAINLEN+1
+ * @param len: length of the buffer on input, length of the result on output.
+ * @return 0 on success, otherwise an error.
+ */
+int sldns_str2wire_dname_buf(const char* str, uint8_t* buf, size_t* len);
+
+/**
+ * Same as sldns_str2wire_dname_buf, but concatenates origin if the domain
+ * name is relative (does not end in '.').
+ * @param str: the text string with the domain name.
+ * @param buf: the result buffer, suggested size LDNS_MAX_DOMAINLEN+1
+ * @param len: length of the buffer on input, length of the result on output.
+ * @param origin: the origin to append or NULL (nothing is appended).
+ * @param origin_len: length of origin.
+ * @return 0 on success, otherwise an error.
+ */
+int sldns_str2wire_dname_buf_origin(const char* str, uint8_t* buf, size_t* len,
+       uint8_t* origin, size_t origin_len);
+
+/**
+ * Convert text string into dname wireformat
+ * @param str: the text string with the domain name.
+ * @param len: returned length of wireformat.
+ * @return wireformat dname (malloced) or NULL on failure.
+ */
+uint8_t* sldns_str2wire_dname(const char* str, size_t* len);
+
+/**
+ * Convert text RR to wireformat, with user buffer.
+ * @param str: the RR data in text presentation format.
+ * @param rr: the buffer where the result is stored into.  This buffer has
+ *     the wire-dname(uncompressed), type, class, ttl, rdatalen, rdata.
+ *     These values are probably not aligned, and in network format.
+ *     Use the sldns_wirerr_get_xxx functions to access them safely.
+ *     buffer size LDNS_RR_BUF_SIZE is suggested.
+ * @param len: on input the length of the buffer, on output the amount of
+ *     the buffer used for the rr.
+ * @param dname_len: if non-NULL, filled with the dname length as result.
+ *     Because after the dname you find the type, class, ttl, rdatalen, rdata.
+ * @param default_ttl: TTL used if no TTL available.
+ * @param origin: used for origin dname (if not NULL)
+ * @param origin_len: length of origin.
+ * @param prev: used for prev_rr dname (if not NULL)
+ * @param prev_len: length of prev.
+ * @return 0 on success, an error on failure.
+ */
+int sldns_str2wire_rr_buf(const char* str, uint8_t* rr, size_t* len,
+       size_t* dname_len, uint32_t default_ttl, uint8_t* origin,
+       size_t origin_len, uint8_t* prev, size_t prev_len);
+
+/**
+ * Same as sldns_str2wire_rr_buf, but there is no rdata, it returns an RR
+ * with zero rdata and no ttl.  It has name, type, class.
+ * You can access those with the sldns_wirerr_get_type and class functions.
+ * @param str: the RR data in text presentation format.
+ * @param rr: the buffer where the result is stored into.
+ * @param len: on input the length of the buffer, on output the amount of
+ *     the buffer used for the rr.
+ * @param dname_len: if non-NULL, filled with the dname length as result.
+ *     Because after the dname you find the type, class, ttl, rdatalen, rdata.
+ * @param origin: used for origin dname (if not NULL)
+ * @param origin_len: length of origin.
+ * @param prev: used for prev_rr dname (if not NULL)
+ * @param prev_len: length of prev.
+ * @return 0 on success, an error on failure.
+ */
+int sldns_str2wire_rr_question_buf(const char* str, uint8_t* rr, size_t* len,
+       size_t* dname_len, uint8_t* origin, size_t origin_len, uint8_t* prev,
+       size_t prev_len);
+
+/**
+ * Get the type of the RR.
+ * @param rr: the RR in wire format.
+ * @param len: rr length.
+ * @param dname_len: dname length to skip.
+ * @return type in host byteorder
+ */
+uint16_t sldns_wirerr_get_type(uint8_t* rr, size_t len, size_t dname_len);
+
+/**
+ * Get the class of the RR.
+ * @param rr: the RR in wire format.
+ * @param len: rr length.
+ * @param dname_len: dname length to skip.
+ * @return class in host byteorder
+ */
+uint16_t sldns_wirerr_get_class(uint8_t* rr, size_t len, size_t dname_len);
+
+/**
+ * Get the ttl of the RR.
+ * @param rr: the RR in wire format.
+ * @param len: rr length.
+ * @param dname_len: dname length to skip.
+ * @return ttl in host byteorder
+ */
+uint32_t sldns_wirerr_get_ttl(uint8_t* rr, size_t len, size_t dname_len);
+
+/**
+ * Get the rdata length of the RR.
+ * @param rr: the RR in wire format.
+ * @param len: rr length.
+ * @param dname_len: dname length to skip.
+ * @return rdata length in host byteorder
+ *     If the rdata length is larger than the rr-len allows, it is truncated.
+ *     So, that it is safe to read the data length returned
+ *     from this function from the rdata pointer of sldns_wirerr_get_rdata.
+ */
+uint16_t sldns_wirerr_get_rdatalen(uint8_t* rr, size_t len, size_t dname_len);
+
+/**
+ * Get the rdata pointer of the RR.
+ * @param rr: the RR in wire format.
+ * @param len: rr length.
+ * @param dname_len: dname length to skip.
+ * @return rdata pointer
+ */
+uint8_t* sldns_wirerr_get_rdata(uint8_t* rr, size_t len, size_t dname_len);
+
+/**
+ * Get the rdata pointer of the RR. prefixed with rdata length.
+ * @param rr: the RR in wire format.
+ * @param len: rr length.
+ * @param dname_len: dname length to skip.
+ * @return pointer to rdatalength, followed by the rdata.
+ */
+uint8_t* sldns_wirerr_get_rdatawl(uint8_t* rr, size_t len, size_t dname_len);
+
+/**
+ * Parse result codes
+ */
+#define LDNS_WIREPARSE_MASK 0x0fff
+#define LDNS_WIREPARSE_SHIFT 12
+#define LDNS_WIREPARSE_ERROR(e) ((e)&LDNS_WIREPARSE_MASK)
+#define LDNS_WIREPARSE_OFFSET(e) (((e)&~LDNS_WIREPARSE_MASK)>>LDNS_WIREPARSE_SHIFT)
+/* use lookuptable to get error string, sldns_wireparse_errors */
+#define LDNS_WIREPARSE_ERR_OK 0
+#define LDNS_WIREPARSE_ERR_GENERAL 342
+#define LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW 343
+#define LDNS_WIREPARSE_ERR_DOMAINNAME_UNDERFLOW 344
+#define LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL 345
+#define LDNS_WIREPARSE_ERR_LABEL_OVERFLOW 346
+#define LDNS_WIREPARSE_ERR_EMPTY_LABEL 347
+#define LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE 348
+#define LDNS_WIREPARSE_ERR_SYNTAX 349
+#define LDNS_WIREPARSE_ERR_SYNTAX_TTL 350
+#define LDNS_WIREPARSE_ERR_SYNTAX_TYPE 351
+#define LDNS_WIREPARSE_ERR_SYNTAX_CLASS 352
+#define LDNS_WIREPARSE_ERR_SYNTAX_RDATA 353
+#define LDNS_WIREPARSE_ERR_SYNTAX_MISSING_VALUE 354
+#define LDNS_WIREPARSE_ERR_INVALID_STR 355
+#define LDNS_WIREPARSE_ERR_SYNTAX_B64 356
+#define LDNS_WIREPARSE_ERR_SYNTAX_B32_EXT 357
+#define LDNS_WIREPARSE_ERR_SYNTAX_HEX 358
+#define LDNS_WIREPARSE_ERR_CERT_BAD_ALGORITHM 359
+#define LDNS_WIREPARSE_ERR_SYNTAX_TIME 360
+#define LDNS_WIREPARSE_ERR_SYNTAX_PERIOD 361
+#define LDNS_WIREPARSE_ERR_SYNTAX_ILNP64 362
+#define LDNS_WIREPARSE_ERR_SYNTAX_EUI48 363
+#define LDNS_WIREPARSE_ERR_SYNTAX_EUI64 364
+#define LDNS_WIREPARSE_ERR_SYNTAX_TAG 365
+#define LDNS_WIREPARSE_ERR_NOT_IMPL 366
+#define LDNS_WIREPARSE_ERR_SYNTAX_INT 367
+#define LDNS_WIREPARSE_ERR_SYNTAX_IP4 368
+#define LDNS_WIREPARSE_ERR_SYNTAX_IP6 369
+#define LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW 370
+#define LDNS_WIREPARSE_ERR_INCLUDE 371
+#define LDNS_WIREPARSE_ERR_PARENTHESIS 372
+
+/**
+ * Get reference to a constant string for the (parse) error.
+ * @param e: error return value
+ * @return string.
+ */
+const char* sldns_get_errorstr_parse(int e);
+
+/**
+ * wire parse state for parsing files
+ */
+struct sldns_file_parse_state {
+       /** the origin domain name, if len!=0. uncompressed wireformat */
+       uint8_t origin[LDNS_MAX_DOMAINLEN+1];
+       /** length of origin domain name, in bytes. 0 if not set. */
+       size_t origin_len;
+       /** the previous domain name, if len!=0. uncompressed wireformat*/
+       uint8_t prev_rr[LDNS_MAX_DOMAINLEN+1];
+       /** length of the previous domain name, in bytes. 0 if not set. */
+       size_t prev_rr_len;
+       /** default TTL, this is used if the text does not specify a TTL,
+        * host byteorder */
+       uint32_t default_ttl;
+       /** line number information */
+       int lineno;
+};
+
+/**
+ * Read one RR from zonefile with buffer for the data.
+ * @param in: file that is read from (one RR, multiple lines if it spans them).
+ * @param rr: this is malloced by the user and the result is stored here,
+ *     if an RR is read.  If no RR is read this is signalled with the
+ *     return len set to 0 (for ORIGIN, TTL directives).
+ * @param len: on input, the length of the rr buffer.  on output the rr len.
+ *     Buffer size of 64k should be enough.
+ * @param dname_len: returns the length of the dname initial part of the rr.
+ * @param parse_state: pass a pointer to user-allocated struct.
+ *     Contents are maintained by this function.
+ *     If you pass NULL then ORIGIN and TTL directives are not honored.
+ *     You can start out with a particular origin by pre-filling it.
+ *     otherwise, zero the structure before passing it.
+ *     lineno is incremented when a newline is passed by the parser,
+ *     you should initialize it at 1 at the start of the file.
+ * @return 0 on success, error on failure.
+ */
+int sldns_fp2wire_rr_buf(FILE* in, uint8_t* rr, size_t* len, size_t* dname_len,
+       struct sldns_file_parse_state* parse_state);
+
+/**
+ * Convert one rdf in rdata to wireformat and parse from string.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @param rdftype: the type of the rdf.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_rdf_buf(const char* str, uint8_t* rd, size_t* len,
+       sldns_rdf_type rdftype);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_INT8 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_int8_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_INT16 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_int16_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_INT32 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_int32_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_A from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_a_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_AAAA from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_aaaa_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_STR from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_str_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_APL from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_apl_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_B64 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_b64_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_B32_EXT from string to wireformat.
+ * And also LDNS_RDF_TYPE_NSEC3_NEXT_OWNER.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_b32_ext_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_HEX from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_hex_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_NSEC from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_nsec_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_TYPE from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_type_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_CLASS from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_class_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_CERT_ALG from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_cert_alg_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_ALG from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_alg_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_TIME from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_time_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_PERIOD from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_period_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_LOC from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_loc_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_WKS from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_wks_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_NSAP from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_nsap_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_ATMA from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_atma_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_IPSECKEY from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_ipseckey_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_NSEC3_SALT from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_nsec3_salt_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_ILNP64 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_ilnp64_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_EUI48 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_eui48_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_EUI64 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_eui64_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_TAG from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_tag_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_LONG_STR from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_long_str_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_HIP from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_hip_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_INT16_DATA from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_int16_data_buf(const char* str, uint8_t* rd, size_t* len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_STR2WIRE_H */
diff --git a/sldns/wire2str.c b/sldns/wire2str.c
new file mode 100644 (file)
index 0000000..cec3bc7
--- /dev/null
@@ -0,0 +1,1967 @@
+/*
+ * wire2str.c
+ *
+ * conversion routines from the wire format
+ * to the presentation format (strings)
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+/**
+ * \file
+ *
+ * Contains functions to translate the wireformat to text
+ * representation, as well as functions to print them.
+ */
+#include "config.h"
+#include "sldns/wire2str.h"
+#include "sldns/str2wire.h"
+#include "sldns/rrdef.h"
+#include "sldns/pkthdr.h"
+#include "sldns/parseutil.h"
+#include "sldns/sbuffer.h"
+#include "sldns/keyraw.h"
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#include <sys/time.h>
+#include <stdarg.h>
+#include <ctype.h>
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+/* lookup tables for standard DNS stuff  */
+/* Taken from RFC 2535, section 7.  */
+static sldns_lookup_table sldns_algorithms_data[] = {
+       { LDNS_RSAMD5, "RSAMD5" },
+       { LDNS_DH, "DH" },
+       { LDNS_DSA, "DSA" },
+       { LDNS_ECC, "ECC" },
+       { LDNS_RSASHA1, "RSASHA1" },
+       { LDNS_DSA_NSEC3, "DSA-NSEC3-SHA1" },
+       { LDNS_RSASHA1_NSEC3, "RSASHA1-NSEC3-SHA1" },
+       { LDNS_RSASHA256, "RSASHA256"},
+       { LDNS_RSASHA512, "RSASHA512"},
+       { LDNS_ECC_GOST, "ECC-GOST"},
+       { LDNS_ECDSAP256SHA256, "ECDSAP256SHA256"},
+       { LDNS_ECDSAP384SHA384, "ECDSAP384SHA384"},
+       { LDNS_INDIRECT, "INDIRECT" },
+       { LDNS_PRIVATEDNS, "PRIVATEDNS" },
+       { LDNS_PRIVATEOID, "PRIVATEOID" },
+       { 0, NULL }
+};
+sldns_lookup_table* sldns_algorithms = sldns_algorithms_data;
+
+/* hash algorithms in DS record */
+static sldns_lookup_table sldns_hashes_data[] = {
+       { LDNS_SHA1, "SHA1" },
+       { LDNS_SHA256, "SHA256" },
+       { LDNS_HASH_GOST, "HASH-GOST" },
+       { LDNS_SHA384, "SHA384" },
+       { 0, NULL }
+};
+sldns_lookup_table* sldns_hashes = sldns_hashes_data;
+
+/* Taken from RFC 4398  */
+static sldns_lookup_table sldns_cert_algorithms_data[] = {
+       { LDNS_CERT_PKIX, "PKIX" },
+       { LDNS_CERT_SPKI, "SPKI" },
+       { LDNS_CERT_PGP, "PGP" },
+       { LDNS_CERT_IPKIX, "IPKIX" },
+       { LDNS_CERT_ISPKI, "ISPKI" },
+       { LDNS_CERT_IPGP, "IPGP" },
+       { LDNS_CERT_ACPKIX, "ACPKIX" },
+       { LDNS_CERT_IACPKIX, "IACPKIX" },
+       { LDNS_CERT_URI, "URI" },
+       { LDNS_CERT_OID, "OID" },
+       { 0, NULL }
+};
+sldns_lookup_table* sldns_cert_algorithms = sldns_cert_algorithms_data;
+
+/* if these are used elsewhere */
+static sldns_lookup_table sldns_rcodes_data[] = {
+       { LDNS_RCODE_NOERROR, "NOERROR" },
+       { LDNS_RCODE_FORMERR, "FORMERR" },
+       { LDNS_RCODE_SERVFAIL, "SERVFAIL" },
+       { LDNS_RCODE_NXDOMAIN, "NXDOMAIN" },
+       { LDNS_RCODE_NOTIMPL, "NOTIMPL" },
+       { LDNS_RCODE_REFUSED, "REFUSED" },
+       { LDNS_RCODE_YXDOMAIN, "YXDOMAIN" },
+       { LDNS_RCODE_YXRRSET, "YXRRSET" },
+       { LDNS_RCODE_NXRRSET, "NXRRSET" },
+       { LDNS_RCODE_NOTAUTH, "NOTAUTH" },
+       { LDNS_RCODE_NOTZONE, "NOTZONE" },
+       { 0, NULL }
+};
+sldns_lookup_table* sldns_rcodes = sldns_rcodes_data;
+
+static sldns_lookup_table sldns_opcodes_data[] = {
+       { LDNS_PACKET_QUERY, "QUERY" },
+       { LDNS_PACKET_IQUERY, "IQUERY" },
+       { LDNS_PACKET_STATUS, "STATUS" },
+       { LDNS_PACKET_NOTIFY, "NOTIFY" },
+       { LDNS_PACKET_UPDATE, "UPDATE" },
+       { 0, NULL }
+};
+sldns_lookup_table* sldns_opcodes = sldns_opcodes_data;
+
+static sldns_lookup_table sldns_wireparse_errors_data[] = {
+       { LDNS_WIREPARSE_ERR_OK, "no parse error" },
+       { LDNS_WIREPARSE_ERR_GENERAL, "parse error" },
+       { LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, "Domainname length overflow" },
+       { LDNS_WIREPARSE_ERR_DOMAINNAME_UNDERFLOW, "Domainname length underflow (zero length)" },
+       { LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, "buffer too small" },
+       { LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, "Label length overflow" },
+       { LDNS_WIREPARSE_ERR_EMPTY_LABEL, "Empty label" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE, "Syntax error, bad escape sequence" },
+       { LDNS_WIREPARSE_ERR_SYNTAX, "Syntax error, could not parse the RR" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_TTL, "Syntax error, could not parse the RR's TTL" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_TYPE, "Syntax error, could not parse the RR's type" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_CLASS, "Syntax error, could not parse the RR's class" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_RDATA, "Syntax error, could not parse the RR's rdata" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_MISSING_VALUE, "Syntax error, value expected" },
+       { LDNS_WIREPARSE_ERR_INVALID_STR, "Conversion error, string expected" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_B64, "Conversion error, b64 encoding expected" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_B32_EXT, "Conversion error, b32 ext encoding expected" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_HEX, "Conversion error, hex encoding expected" },
+       { LDNS_WIREPARSE_ERR_CERT_BAD_ALGORITHM, "Bad algorithm type for CERT record" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_TIME, "Conversion error, time encoding expected" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_PERIOD, "Conversion error, time period encoding expected" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_ILNP64, "Conversion error, 4 colon separated hex numbers expected" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_EUI48,
+               "Conversion error, 6 two character hex numbers "
+               "separated by dashes expected (i.e. xx-xx-xx-xx-xx-xx" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_EUI64,
+               "Conversion error, 8 two character hex numbers "
+               "separated by dashes expected (i.e. xx-xx-xx-xx-xx-xx-xx-xx" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_TAG,
+               "Conversion error, a non-zero sequence of US-ASCII letters "
+               "and numbers in lower case expected" },
+       { LDNS_WIREPARSE_ERR_NOT_IMPL, "not implemented" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_INT, "Conversion error, integer expected" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_IP4, "Conversion error, ip4 addr expected" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_IP6, "Conversion error, ip6 addr expected" },
+       { LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW, "Syntax error, integer overflow" },
+       { LDNS_WIREPARSE_ERR_INCLUDE, "$INCLUDE directive was seen in the zone" },
+       { LDNS_WIREPARSE_ERR_PARENTHESIS, "Parse error, parenthesis mismatch" },
+       { 0, NULL }
+};
+sldns_lookup_table* sldns_wireparse_errors = sldns_wireparse_errors_data;
+
+static sldns_lookup_table sldns_edns_flags_data[] = {
+       { 3600, "do"},
+       { 0, NULL}
+};
+sldns_lookup_table* sldns_edns_flags = sldns_edns_flags_data;
+
+static sldns_lookup_table sldns_edns_options_data[] = {
+       { 1, "LLQ" },
+       { 2, "UL" },
+       { 3, "NSID" },
+       /* 4 draft-cheshire-edns0-owner-option */
+       { 5, "DAU" },
+       { 6, "DHU" },
+       { 7, "N3U" },
+       { 8, "edns-client-subnet" },
+       { 0, NULL}
+};
+sldns_lookup_table* sldns_edns_options = sldns_edns_options_data;
+
+char* sldns_wire2str_pkt(uint8_t* data, size_t len)
+{
+       size_t slen = (size_t)sldns_wire2str_pkt_buf(data, len, NULL, 0);
+       char* result = (char*)malloc(slen+1);
+       if(!result) return NULL;
+       sldns_wire2str_pkt_buf(data, len, result, slen+1);
+       return result;
+}
+
+char* sldns_wire2str_rr(uint8_t* rr, size_t len)
+{
+       size_t slen = (size_t)sldns_wire2str_rr_buf(rr, len, NULL, 0);
+       char* result = (char*)malloc(slen+1);
+       if(!result) return NULL;
+       sldns_wire2str_rr_buf(rr, len, result, slen+1);
+       return result;
+}
+
+char* sldns_wire2str_type(uint16_t rrtype)
+{
+       char buf[16];
+       sldns_wire2str_type_buf(rrtype, buf, sizeof(buf));
+       return strdup(buf);
+}
+
+char* sldns_wire2str_class(uint16_t rrclass)
+{
+       char buf[16];
+       sldns_wire2str_class_buf(rrclass, buf, sizeof(buf));
+       return strdup(buf);
+}
+
+char* sldns_wire2str_dname(uint8_t* dname, size_t dname_len)
+{
+       size_t slen=(size_t)sldns_wire2str_dname_buf(dname, dname_len, NULL, 0);
+       char* result = (char*)malloc(slen+1);
+       if(!result) return NULL;
+       sldns_wire2str_dname_buf(dname, dname_len, result, slen+1);
+       return result;
+}
+
+char* sldns_wire2str_rcode(int rcode)
+{
+       char buf[16];
+       sldns_wire2str_rcode_buf(rcode, buf, sizeof(buf));
+       return strdup(buf);
+}
+
+int sldns_wire2str_pkt_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
+{
+       /* use arguments as temporary variables */
+       return sldns_wire2str_pkt_scan(&d, &dlen, &s, &slen);
+}
+
+int sldns_wire2str_rr_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
+{
+       /* use arguments as temporary variables */
+       return sldns_wire2str_rr_scan(&d, &dlen, &s, &slen, NULL, 0);
+}
+
+int sldns_wire2str_rdata_buf(uint8_t* rdata, size_t rdata_len, char* str,
+       size_t str_len, uint16_t rrtype)
+{
+       /* use arguments as temporary variables */
+       return sldns_wire2str_rdata_scan(&rdata, &rdata_len, &str, &str_len,
+               rrtype, NULL, 0);
+}
+
+int sldns_wire2str_rr_unknown_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
+{
+       /* use arguments as temporary variables */
+       return sldns_wire2str_rr_unknown_scan(&d, &dlen, &s, &slen, NULL, 0);
+}
+
+int sldns_wire2str_rr_comment_buf(uint8_t* rr, size_t rrlen, size_t dname_len,
+       char* s, size_t slen)
+{
+       uint16_t rrtype = sldns_wirerr_get_type(rr, rrlen, dname_len);
+       return sldns_wire2str_rr_comment_print(&s, &slen, rr, rrlen, dname_len,
+               rrtype);
+}
+
+int sldns_wire2str_type_buf(uint16_t rrtype, char* s, size_t slen)
+{
+       /* use arguments as temporary variables */
+       return sldns_wire2str_type_print(&s, &slen, rrtype);
+}
+
+int sldns_wire2str_class_buf(uint16_t rrclass, char* s, size_t slen)
+{
+       /* use arguments as temporary variables */
+       return sldns_wire2str_class_print(&s, &slen, rrclass);
+}
+
+int sldns_wire2str_rcode_buf(int rcode, char* s, size_t slen)
+{
+       /* use arguments as temporary variables */
+       return sldns_wire2str_rcode_print(&s, &slen, rcode);
+}
+
+int sldns_wire2str_dname_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
+{
+       /* use arguments as temporary variables */
+       return sldns_wire2str_dname_scan(&d, &dlen, &s, &slen, NULL, 0);
+}
+
+int sldns_str_vprint(char** str, size_t* slen, const char* format, va_list args)
+{
+       int w = vsnprintf(*str, *slen, format, args);
+       if(w < 0) {
+               /* error in printout */
+               return 0;
+       } else if((size_t)w >= *slen) {
+               *str = NULL; /* we do not want str to point outside of buffer*/
+               *slen = 0;
+       } else {
+               *str += w;
+               *slen -= w;
+       }
+       return w;
+}
+
+int sldns_str_print(char** str, size_t* slen, const char* format, ...)
+{
+       int w;
+       va_list args;
+       va_start(args, format);
+       w = sldns_str_vprint(str, slen, format, args);
+       va_end(args);
+       return w;
+}
+
+/** print hex format into text buffer for specified length */
+static int print_hex_buf(char** s, size_t* slen, uint8_t* buf, size_t len)
+{
+       const char* hex = "0123456789ABCDEF";
+       size_t i;
+       for(i=0; i<len; i++) {
+               (void)sldns_str_print(s, slen, "%c%c", hex[(buf[i]&0xf0)>>4],
+                       hex[buf[i]&0x0f]);
+       }
+       return (int)len*2;
+}
+
+/** print remainder of buffer in hex format with prefixed text */
+static int print_remainder_hex(const char* pref, uint8_t** d, size_t* dlen,
+       char** s, size_t* slen)
+{
+       int w = 0;
+       w += sldns_str_print(s, slen, "%s", pref);
+       w += print_hex_buf(s, slen, *d, *dlen);
+       *d += *dlen;
+       *dlen = 0;
+       return w;
+}
+
+int sldns_wire2str_pkt_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
+{
+       int w = 0;
+       unsigned qdcount, ancount, nscount, arcount, i;
+       uint8_t* pkt = *d;
+       size_t pktlen = *dlen;
+       if(*dlen >= LDNS_HEADER_SIZE) {
+               qdcount = (unsigned)LDNS_QDCOUNT(*d);
+               ancount = (unsigned)LDNS_ANCOUNT(*d);
+               nscount = (unsigned)LDNS_NSCOUNT(*d);
+               arcount = (unsigned)LDNS_ARCOUNT(*d);
+       } else {
+               qdcount = ancount = nscount = arcount = 0;
+       }
+       w += sldns_wire2str_header_scan(d, dlen, s, slen);
+       w += sldns_str_print(s, slen, "\n");
+       w += sldns_str_print(s, slen, ";; QUESTION SECTION:\n");
+       for(i=0; i<qdcount; i++) {
+               w += sldns_wire2str_rrquestion_scan(d, dlen, s, slen,
+                       pkt, pktlen);
+               if(!*dlen) break;
+       }
+       w += sldns_str_print(s, slen, "\n");
+       w += sldns_str_print(s, slen, ";; ANSWER SECTION:\n");
+       for(i=0; i<ancount; i++) {
+               w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen);
+               if(!*dlen) break;
+       }
+       w += sldns_str_print(s, slen, "\n");
+       w += sldns_str_print(s, slen, ";; AUTHORITY SECTION:\n");
+       for(i=0; i<nscount; i++) {
+               w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen);
+               if(!*dlen) break;
+       }
+       w += sldns_str_print(s, slen, "\n");
+       w += sldns_str_print(s, slen, ";; ADDITIONAL SECTION:\n");
+       for(i=0; i<arcount; i++) {
+               w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen);
+               if(!*dlen) break;
+       }
+       /* other fields: WHEN(time), SERVER(IP) not available here. */
+       w += sldns_str_print(s, slen, ";; MSG SIZE  rcvd: %d\n", (int)pktlen);
+       if(*dlen > 0) {
+               w += print_remainder_hex(";; trailing garbage 0x",
+                       d, dlen, s, slen);
+               w += sldns_str_print(s, slen, "\n");
+       }
+       return w;
+}
+
+/** scan type, class and ttl and printout, for rr */
+static int sldns_rr_tcttl_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       int w = 0;
+       uint16_t t, c;
+       uint32_t ttl;
+       if(*dl < 8) {
+               if(*dl < 4)
+                       return w + print_remainder_hex("; Error malformed 0x",
+                               d, dl, s, sl);
+               /* these print values or 0x.. if none left */
+               t = sldns_read_uint16(*d);
+               c = sldns_read_uint16((*d)+2);
+               (*d)+=4;
+               (*dl)-=4;
+               w += sldns_wire2str_class_print(s, sl, c);
+               w += sldns_str_print(s, sl, "\t");
+               w += sldns_wire2str_type_print(s, sl, t);
+               if(*dl == 0)
+                       return w + sldns_str_print(s, sl, "; Error no ttl");
+               return w + print_remainder_hex(
+                       "; Error malformed ttl 0x", d, dl, s, sl);
+       }
+       t = sldns_read_uint16(*d);
+       c = sldns_read_uint16((*d)+2);
+       ttl = sldns_read_uint32((*d)+4);
+       (*d)+=8;
+       (*dl)-=8;
+       w += sldns_str_print(s, sl, "%lu\t", (unsigned long)ttl);
+       w += sldns_wire2str_class_print(s, sl, c);
+       w += sldns_str_print(s, sl, "\t");
+       w += sldns_wire2str_type_print(s, sl, t);
+       return w;
+}
+
+int sldns_wire2str_rr_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
+       uint8_t* pkt, size_t pktlen)
+{
+       int w = 0;
+       uint8_t* rr = *d;
+       size_t rrlen = *dlen, dname_off, rdlen, ordlen;
+       uint16_t rrtype = 0;
+       
+       if(*dlen >= 3 && (*d)[0]==0 &&
+               sldns_read_uint16((*d)+1)==LDNS_RR_TYPE_OPT) {
+               /* perform EDNS OPT processing */
+               return sldns_wire2str_edns_scan(d, dlen, s, slen, pkt, pktlen);
+       }
+
+       /* try to scan the rdata with pretty-printing, but if that fails, then
+        * scan the rdata as an unknown RR type */
+       w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
+       w += sldns_str_print(s, slen, "\t");
+       dname_off = rrlen-(*dlen);
+       if(*dlen == 4) {
+               /* like a question-RR */
+               uint16_t t = sldns_read_uint16(*d);
+               uint16_t c = sldns_read_uint16((*d)+2);
+               (*d)+=4;
+               (*dlen)-=4;
+               w += sldns_wire2str_class_print(s, slen, c);
+               w += sldns_str_print(s, slen, "\t");
+               w += sldns_wire2str_type_print(s, slen, t);
+               w += sldns_str_print(s, slen, " ; Error no ttl,rdata\n");
+               return w;
+       }
+       if(*dlen < 8) {
+               if(*dlen == 0)
+                       return w + sldns_str_print(s, slen, ";Error missing RR\n");
+               w += print_remainder_hex(";Error partial RR 0x", d, dlen, s, slen);
+               return w + sldns_str_print(s, slen, "\n");
+       }
+       rrtype = sldns_read_uint16(*d);
+       w += sldns_rr_tcttl_scan(d, dlen, s, slen);
+       w += sldns_str_print(s, slen, "\t");
+
+       /* rdata */
+       if(*dlen < 2) {
+               if(*dlen == 0)
+                       return w + sldns_str_print(s, slen, ";Error missing rdatalen\n");
+               w += print_remainder_hex(";Error missing rdatalen 0x",
+                       d, dlen, s, slen);
+               return w + sldns_str_print(s, slen, "\n");
+       }
+       rdlen = sldns_read_uint16(*d);
+       ordlen = rdlen;
+       (*d)+=2;
+       (*dlen)-=2;
+       if(*dlen < rdlen) {
+               w += sldns_str_print(s, slen, "\\# %u ", (unsigned)rdlen);
+               if(*dlen == 0)
+                       return w + sldns_str_print(s, slen, ";Error missing rdata\n");
+               w += print_remainder_hex(";Error partial rdata 0x", d, dlen, s, slen);
+               return w + sldns_str_print(s, slen, "\n");
+       }
+       w += sldns_wire2str_rdata_scan(d, &rdlen, s, slen, rrtype, pkt, pktlen);
+       (*dlen) -= (ordlen-rdlen);
+
+       /* default comment */
+       w += sldns_wire2str_rr_comment_print(s, slen, rr, rrlen, dname_off,
+               rrtype);
+       w += sldns_str_print(s, slen, "\n");
+       return w;
+}
+
+int sldns_wire2str_rrquestion_scan(uint8_t** d, size_t* dlen, char** s,
+       size_t* slen, uint8_t* pkt, size_t pktlen)
+{
+       int w = 0;
+       uint16_t t, c;
+       w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
+       w += sldns_str_print(s, slen, "\t");
+       if(*dlen < 4) {
+               if(*dlen == 0)
+                       return w + sldns_str_print(s, slen, "Error malformed\n");
+               w += print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
+               return w + sldns_str_print(s, slen, "\n");
+       }
+       t = sldns_read_uint16(*d);
+       c = sldns_read_uint16((*d)+2);
+       (*d)+=4;
+       (*dlen)-=4;
+       w += sldns_wire2str_class_print(s, slen, c);
+       w += sldns_str_print(s, slen, "\t");
+       w += sldns_wire2str_type_print(s, slen, t);
+       w += sldns_str_print(s, slen, "\n");
+       return w;
+}
+
+int sldns_wire2str_rr_unknown_scan(uint8_t** d, size_t* dlen, char** s,
+       size_t* slen, uint8_t* pkt, size_t pktlen)
+{
+       size_t rdlen, ordlen;
+       int w = 0;
+       w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
+       w += sldns_str_print(s, slen, "\t");
+       w += sldns_rr_tcttl_scan(d, dlen, s, slen);
+       w += sldns_str_print(s, slen, "\t");
+       if(*dlen < 2) {
+               if(*dlen == 0)
+                       return w + sldns_str_print(s, slen, ";Error missing rdatalen\n");
+               w += print_remainder_hex(";Error missing rdatalen 0x",
+                       d, dlen, s, slen);
+               return w + sldns_str_print(s, slen, "\n");
+       }
+       rdlen = sldns_read_uint16(*d);
+       ordlen = rdlen;
+       (*d) += 2;
+       (*dlen) -= 2;
+       if(*dlen < rdlen) {
+               w += sldns_str_print(s, slen, "\\# %u ", (unsigned)rdlen);
+               if(*dlen == 0)
+                       return w + sldns_str_print(s, slen, ";Error missing rdata\n");
+               w += print_remainder_hex(";Error partial rdata 0x", d, dlen, s, slen);
+               return w + sldns_str_print(s, slen, "\n");
+       }
+       w += sldns_wire2str_rdata_unknown_scan(d, &rdlen, s, slen);
+       (*dlen) -= (ordlen-rdlen);
+       w += sldns_str_print(s, slen, "\n");
+       return w;
+}
+
+/** print rr comment for type DNSKEY */
+static int rr_comment_dnskey(char** s, size_t* slen, uint8_t* rr,
+       size_t rrlen, size_t dname_off)
+{
+       size_t rdlen;
+       uint8_t* rdata;
+       int flags, w = 0;
+       if(rrlen < dname_off + 10) return 0;
+       rdlen = sldns_read_uint16(rr+dname_off+8);
+       if(rrlen < dname_off + 10 + rdlen) return 0;
+       rdata = rr + dname_off + 10;
+       flags = (int)sldns_read_uint16(rdata);
+       w += sldns_str_print(s, slen, " ;{");
+
+       /* id */
+       w += sldns_str_print(s, slen, "id = %u",
+               sldns_calc_keytag_raw(rdata, rdlen));
+
+       /* flags */
+       if((flags&LDNS_KEY_ZONE_KEY)) {
+               if((flags&LDNS_KEY_SEP_KEY))
+                       w += sldns_str_print(s, slen, " (ksk)");
+               else    w += sldns_str_print(s, slen, " (zsk)");
+       }
+
+       /* keysize */
+       if(rdlen > 4) {
+               w += sldns_str_print(s, slen, ", ");
+               w += sldns_str_print(s, slen, "size = %db",
+                       (int)sldns_rr_dnskey_key_size_raw(
+                       (unsigned char*)rdata+4, rdlen-4, (int)(rdata[3])));
+       }
+
+       w += sldns_str_print(s, slen, "}");
+       return w;
+}
+
+/** print rr comment for type RRSIG */
+static int rr_comment_rrsig(char** s, size_t* slen, uint8_t* rr,
+       size_t rrlen, size_t dname_off)
+{
+       size_t rdlen;
+       uint8_t* rdata;
+       if(rrlen < dname_off + 10) return 0;
+       rdlen = sldns_read_uint16(rr+dname_off+8);
+       if(rrlen < dname_off + 10 + rdlen) return 0;
+       rdata = rr + dname_off + 10;
+       if(rdlen < 18) return 0;
+       return sldns_str_print(s, slen, " ;{id = %d}",
+               (int)sldns_read_uint16(rdata+16));
+}
+
+/** print rr comment for type NSEC3 */
+static int rr_comment_nsec3(char** s, size_t* slen, uint8_t* rr,
+       size_t rrlen, size_t dname_off)
+{
+       size_t rdlen;
+       uint8_t* rdata;
+       int w = 0;
+       if(rrlen < dname_off + 10) return 0;
+       rdlen = sldns_read_uint16(rr+dname_off+8);
+       if(rrlen < dname_off + 10 + rdlen) return 0;
+       rdata = rr + dname_off + 10;
+       if(rdlen < 2) return 0;
+       if((rdata[1] & LDNS_NSEC3_VARS_OPTOUT_MASK))
+               w += sldns_str_print(s, slen, " ;{flags: optout}");
+       return w;
+}
+
+int sldns_wire2str_rr_comment_print(char** s, size_t* slen, uint8_t* rr,
+       size_t rrlen, size_t dname_off, uint16_t rrtype)
+{
+       if(rrtype == LDNS_RR_TYPE_DNSKEY) {
+               return rr_comment_dnskey(s, slen, rr, rrlen, dname_off);
+       } else if(rrtype == LDNS_RR_TYPE_RRSIG) {
+               return rr_comment_rrsig(s, slen, rr, rrlen, dname_off);
+       } else if(rrtype == LDNS_RR_TYPE_NSEC3) {
+               return rr_comment_nsec3(s, slen, rr, rrlen, dname_off);
+       }
+       return 0;
+}
+
+int sldns_wire2str_header_scan(uint8_t** d, size_t* dlen, char** s,
+       size_t* slen)
+{
+       int w = 0;
+       int opcode, rcode;
+       w += sldns_str_print(s, slen, ";; ->>HEADER<<- ");
+       if(*dlen == 0)
+               return w+sldns_str_print(s, slen, "Error empty packet");
+       if(*dlen < 4)
+               return w+print_remainder_hex("Error header too short 0x", d, dlen, s, slen);
+       opcode = (int)LDNS_OPCODE_WIRE(*d);
+       rcode = (int)LDNS_RCODE_WIRE(*d);
+       w += sldns_str_print(s, slen, "opcode: ");
+       w += sldns_wire2str_opcode_print(s, slen, opcode);
+       w += sldns_str_print(s, slen, ", ");
+       w += sldns_str_print(s, slen, "rcode: ");
+       w += sldns_wire2str_rcode_print(s, slen, rcode);
+       w += sldns_str_print(s, slen, ", ");
+       w += sldns_str_print(s, slen, "id: %d\n", (int)LDNS_ID_WIRE(*d));
+       w += sldns_str_print(s, slen, ";; flags:");
+       if(LDNS_QR_WIRE(*d)) w += sldns_str_print(s, slen, " qr");
+       if(LDNS_AA_WIRE(*d)) w += sldns_str_print(s, slen, " aa");
+       if(LDNS_TC_WIRE(*d)) w += sldns_str_print(s, slen, " tc");
+       if(LDNS_RD_WIRE(*d)) w += sldns_str_print(s, slen, " rd");
+       if(LDNS_CD_WIRE(*d)) w += sldns_str_print(s, slen, " cd");
+       if(LDNS_RA_WIRE(*d)) w += sldns_str_print(s, slen, " ra");
+       if(LDNS_AD_WIRE(*d)) w += sldns_str_print(s, slen, " ad");
+       if(LDNS_Z_WIRE(*d))  w += sldns_str_print(s, slen, " z");
+       w += sldns_str_print(s, slen, " ; ");
+       if(*dlen < LDNS_HEADER_SIZE)
+               return w+print_remainder_hex("Error header too short 0x", d, dlen, s, slen);
+       w += sldns_str_print(s, slen, "QUERY: %d, ", (int)LDNS_QDCOUNT(*d));
+       w += sldns_str_print(s, slen, "ANSWER: %d, ", (int)LDNS_ANCOUNT(*d));
+       w += sldns_str_print(s, slen, "AUTHORITY: %d, ", (int)LDNS_NSCOUNT(*d));
+       w += sldns_str_print(s, slen, "ADDITIONAL: %d ", (int)LDNS_ARCOUNT(*d));
+       *d += LDNS_HEADER_SIZE;
+       *dlen -= LDNS_HEADER_SIZE;
+       return w;
+}
+
+int sldns_wire2str_rdata_scan(uint8_t** d, size_t* dlen, char** s,
+       size_t* slen, uint16_t rrtype, uint8_t* pkt, size_t pktlen)
+{
+       /* try to prettyprint, but if that fails, use unknown format */
+       uint8_t* origd = *d;
+       char* origs = *s;
+       size_t origdlen = *dlen, origslen = *slen;
+       uint16_t r_cnt, r_max;
+       sldns_rdf_type rdftype;
+       int w = 0, n;
+
+       const sldns_rr_descriptor *desc = sldns_rr_descript(rrtype);
+       if(!desc) /* unknown format */
+               return sldns_wire2str_rdata_unknown_scan(d, dlen, s, slen);
+       /* dlen equals the rdatalen for the rdata */
+
+       r_max = sldns_rr_descriptor_maximum(desc);
+       for(r_cnt=0; r_cnt < r_max; r_cnt++) {
+               if(*dlen == 0) {
+                       if(r_cnt < sldns_rr_descriptor_minimum(desc))
+                               goto failed;
+                       break; /* nothing more to print */
+               }
+               rdftype = sldns_rr_descriptor_field_type(desc, r_cnt);
+               if(r_cnt != 0)
+                       w += sldns_str_print(s, slen, " ");
+               n = sldns_wire2str_rdf_scan(d, dlen, s, slen, rdftype,
+                       pkt, pktlen);
+               if(n == -1) {
+               failed:
+                       /* failed, use unknown format */
+                       *d = origd; *s = origs;
+                       *dlen = origdlen; *slen = origslen;
+                       return sldns_wire2str_rdata_unknown_scan(d, dlen,
+                               s, slen);
+               }
+               w += n;
+       }
+       return w;
+}
+
+int sldns_wire2str_rdata_unknown_scan(uint8_t** d, size_t* dlen, char** s,
+       size_t* slen)
+{
+       int w = 0;
+
+       /* print length */
+       w += sldns_str_print(s, slen, "\\# %u", (unsigned)*dlen);
+
+       /* print rdlen in hex */
+       if(*dlen != 0)
+               w += sldns_str_print(s, slen, " ");
+       w += print_hex_buf(s, slen, *d, *dlen);
+       (*d) += *dlen;
+       (*dlen) = 0;
+       return w;
+}
+
+/** print and escape one character for a domain dname */
+static int dname_char_print(char** s, size_t* slen, uint8_t c)
+{
+       if(c == '.' || c == ';' || c == '(' || c == ')' || c == '\\')
+               return sldns_str_print(s, slen, "\\%c", c);
+       else if(!(isascii((unsigned char)c) && isgraph((unsigned char)c)))
+               return sldns_str_print(s, slen, "\\%03u", (unsigned)c);
+       /* plain printout */
+       if(*slen) {
+               **s = (char)c;
+               (*s)++;
+               (*slen)--;
+       }
+       return 1;
+}
+
+int sldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
+       uint8_t* pkt, size_t pktlen)
+{
+       int w = 0;
+       /* spool labels onto the string, use compression if its there */
+       uint8_t* pos = *d;
+       unsigned i, counter=0;
+       const unsigned maxcompr = 1000; /* loop detection, max compr ptrs */
+       int in_buf = 1;
+       if(*dlen == 0) return sldns_str_print(s, slen, "ErrorMissingDname");
+       if(*pos == 0) {
+               (*d)++;
+               (*dlen)--;
+               return sldns_str_print(s, slen, ".");
+       }
+       while(*pos) {
+               /* read label length */
+               uint8_t labellen = *pos++;
+               if(in_buf) { (*d)++; (*dlen)--; }
+
+               /* find out what sort of label we have */
+               if((labellen&0xc0) == 0xc0) {
+                       /* compressed */
+                       uint16_t target = 0;
+                       if(in_buf && *dlen == 0)
+                               return w + sldns_str_print(s, slen,
+                                       "ErrorPartialDname");
+                       else if(!in_buf && pos+1 > pkt+pktlen)
+                               return w + sldns_str_print(s, slen,
+                                       "ErrorPartialDname");
+                       target = ((labellen&0x3f)<<8) | *pos;
+                       if(in_buf) { (*d)++; (*dlen)--; }
+                       /* move to target, if possible */
+                       if(!pkt || target >= pktlen)
+                               return w + sldns_str_print(s, slen,
+                                       "ErrorComprPtrOutOfBounds");
+                       if(counter++ > maxcompr)
+                               return w + sldns_str_print(s, slen,
+                                       "ErrorComprPtrLooped");
+                       in_buf = 0;
+                       pos = pkt+target;
+                       continue;
+               } else if((labellen&0xc0)) {
+                       /* notimpl label type */
+                       w += sldns_str_print(s, slen,
+                               "ErrorLABELTYPE%xIsUnknown",
+                               (int)(labellen&0xc0));
+                       return w;
+               }
+
+               /* spool label characters, end with '.' */
+               if(in_buf && *dlen < labellen) labellen = *dlen;
+               else if(!in_buf && pos+labellen > pkt+pktlen)
+                       labellen = (uint8_t)(pkt + pktlen - pos);
+               for(i=0; i<(unsigned)labellen; i++) {
+                       w += dname_char_print(s, slen, *pos++);
+               }
+               if(in_buf) {
+                       (*d) += labellen;
+                       (*dlen) -= labellen;
+                       if(*dlen == 0) break;
+               }
+               w += sldns_str_print(s, slen, ".");
+       }
+       /* skip over final root label */
+       if(in_buf && *dlen > 0) { (*d)++; (*dlen)--; }
+       /* in case we printed no labels, terminate dname */
+       if(w == 0) w += sldns_str_print(s, slen, ".");
+       return w;
+}
+
+int sldns_wire2str_opcode_print(char** s, size_t* slen, int opcode)
+{
+       sldns_lookup_table *lt = sldns_lookup_by_id(sldns_opcodes, opcode);
+       if (lt && lt->name) {
+               return sldns_str_print(s, slen, "%s", lt->name);
+       }
+       return sldns_str_print(s, slen, "OPCODE%u", (unsigned)opcode);
+}
+
+int sldns_wire2str_rcode_print(char** s, size_t* slen, int rcode)
+{
+       sldns_lookup_table *lt = sldns_lookup_by_id(sldns_rcodes, rcode);
+       if (lt && lt->name) {
+               return sldns_str_print(s, slen, "%s", lt->name);
+       }
+       return sldns_str_print(s, slen, "RCODE%u", (unsigned)rcode);
+}
+
+int sldns_wire2str_class_print(char** s, size_t* slen, uint16_t rrclass)
+{
+       sldns_lookup_table *lt = sldns_lookup_by_id(sldns_rr_classes,
+               (int)rrclass);
+       if (lt && lt->name) {
+               return sldns_str_print(s, slen, "%s", lt->name);
+       }
+       return sldns_str_print(s, slen, "CLASS%u", (unsigned)rrclass);
+}
+
+int sldns_wire2str_type_print(char** s, size_t* slen, uint16_t rrtype)
+{
+       const sldns_rr_descriptor *descriptor = sldns_rr_descript(rrtype);
+       if (descriptor && descriptor->_name) {
+               return sldns_str_print(s, slen, "%s", descriptor->_name);
+       }
+       return sldns_str_print(s, slen, "TYPE%u", (unsigned)rrtype);
+}
+
+int sldns_wire2str_edns_option_code_print(char** s, size_t* slen,
+       uint16_t opcode)
+{
+       sldns_lookup_table *lt = sldns_lookup_by_id(sldns_edns_options,
+               (int)opcode);
+       if (lt && lt->name) {
+               return sldns_str_print(s, slen, "%s", lt->name);
+       }
+       return sldns_str_print(s, slen, "OPT%u", (unsigned)opcode);
+}
+
+int sldns_wire2str_class_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
+{
+       uint16_t c;
+       if(*dlen == 0) return 0;
+       if(*dlen < 2) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
+       c = sldns_read_uint16(*d);
+       (*d)+=2;
+       (*dlen)-=2;
+       return sldns_wire2str_class_print(s, slen, c);
+}
+
+int sldns_wire2str_type_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
+{
+       uint16_t t;
+       if(*dlen == 0) return 0;
+       if(*dlen < 2) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
+       t = sldns_read_uint16(*d);
+       (*d)+=2;
+       (*dlen)-=2;
+       return sldns_wire2str_type_print(s, slen, t);
+}
+
+int sldns_wire2str_ttl_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
+{
+       uint32_t ttl;
+       if(*dlen == 0) return 0;
+       if(*dlen < 4) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
+       ttl = sldns_read_uint32(*d);
+       (*d)+=4;
+       (*dlen)-=4;
+       return sldns_str_print(s, slen, "%u", (unsigned)ttl);
+}
+
+int sldns_wire2str_rdf_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
+       int rdftype, uint8_t* pkt, size_t pktlen)
+{
+       if(*dlen == 0) return 0;
+       switch(rdftype) {
+       case LDNS_RDF_TYPE_NONE:
+               return 0;
+       case LDNS_RDF_TYPE_DNAME:
+               return sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
+       case LDNS_RDF_TYPE_INT8:
+               return sldns_wire2str_int8_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_INT16:
+               return sldns_wire2str_int16_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_INT32:
+               return sldns_wire2str_int32_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_PERIOD:
+               return sldns_wire2str_period_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_TSIGTIME:
+               return sldns_wire2str_tsigtime_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_A:
+               return sldns_wire2str_a_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_AAAA:
+               return sldns_wire2str_aaaa_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_STR:
+               return sldns_wire2str_str_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_APL:
+               return sldns_wire2str_apl_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_B32_EXT:
+               return sldns_wire2str_b32_ext_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_B64:
+               return sldns_wire2str_b64_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_HEX:
+               return sldns_wire2str_hex_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_NSEC:
+               return sldns_wire2str_nsec_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_NSEC3_SALT:
+               return sldns_wire2str_nsec3_salt_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_TYPE:
+               return sldns_wire2str_type_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_CLASS:
+               return sldns_wire2str_class_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_CERT_ALG:
+               return sldns_wire2str_cert_alg_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_ALG:
+               return sldns_wire2str_alg_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_UNKNOWN:
+               return sldns_wire2str_unknown_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_TIME:
+               return sldns_wire2str_time_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_LOC:
+               return sldns_wire2str_loc_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_WKS:
+       case LDNS_RDF_TYPE_SERVICE:
+               return sldns_wire2str_wks_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_NSAP:
+               return sldns_wire2str_nsap_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_ATMA:
+               return sldns_wire2str_atma_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_IPSECKEY:
+               return sldns_wire2str_ipseckey_scan(d, dlen, s, slen, pkt,
+                       pktlen);
+       case LDNS_RDF_TYPE_HIP:
+               return sldns_wire2str_hip_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_INT16_DATA:
+               return sldns_wire2str_int16_data_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
+               return sldns_wire2str_b32_ext_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_ILNP64:
+               return sldns_wire2str_ilnp64_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_EUI48:
+               return sldns_wire2str_eui48_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_EUI64:
+               return sldns_wire2str_eui64_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_TAG:
+               return sldns_wire2str_tag_scan(d, dlen, s, slen);
+       case LDNS_RDF_TYPE_LONG_STR:
+               return sldns_wire2str_long_str_scan(d, dlen, s, slen);
+       }
+       /* unknown rdf type */
+       return -1;
+}
+
+int sldns_wire2str_int8_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       int w;
+       if(*dl < 1) return -1;
+       w = sldns_str_print(s, sl, "%u", (unsigned)**d);
+       (*d)++;
+       (*dl)--;
+       return w;
+}
+
+int sldns_wire2str_int16_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       int w;
+       if(*dl < 2) return -1;
+       w = sldns_str_print(s, sl, "%lu", (unsigned long)sldns_read_uint16(*d));
+       (*d)+=2;
+       (*dl)-=2;
+       return w;
+}
+
+int sldns_wire2str_int32_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       int w;
+       if(*dl < 4) return -1;
+       w = sldns_str_print(s, sl, "%lu", (unsigned long)sldns_read_uint32(*d));
+       (*d)+=4;
+       (*dl)-=4;
+       return w;
+}
+
+int sldns_wire2str_period_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       int w;
+       if(*dl < 4) return -1;
+       w = sldns_str_print(s, sl, "%u", (unsigned)sldns_read_uint32(*d));
+       (*d)+=4;
+       (*dl)-=4;
+       return w;
+}
+
+int sldns_wire2str_tsigtime_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       /* tsigtime is 48 bits network order unsigned integer */
+       int w;
+       uint64_t tsigtime = 0;
+       uint64_t d0, d1, d2, d3, d4, d5;
+       if(*dl < 6) return -1;
+       d0 = (*d)[0]; /* cast to uint64 for shift operations */
+       d1 = (*d)[1];
+       d2 = (*d)[2];
+       d3 = (*d)[3];
+       d4 = (*d)[4];
+       d5 = (*d)[5];
+       tsigtime = (d0<<40) | (d1<<32) | (d2<<24) | (d3<<16) | (d4<<8) | d5;
+#ifndef USE_WINSOCK
+       w = sldns_str_print(s, sl, "%llu", (long long)tsigtime);
+#else
+       w = sldns_str_print(s, sl, "%I64u", (long long)tsigtime);
+#endif
+       (*d)+=6;
+       (*dl)-=6;
+       return w;
+}
+
+int sldns_wire2str_a_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       char buf[32];
+       int w;
+       if(*dl < 4) return -1;
+       if(!inet_ntop(AF_INET, *d, buf, (socklen_t)sizeof(buf)))
+               return -1;
+       w = sldns_str_print(s, sl, "%s", buf);
+       (*d)+=4;
+       (*dl)-=4;
+       return w;
+}
+
+int sldns_wire2str_aaaa_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+#ifdef AF_INET6
+       char buf[64];
+       int w;
+       if(*dl < 16) return -1;
+       if(!inet_ntop(AF_INET6, *d, buf, (socklen_t)sizeof(buf)))
+               return -1;
+       w = sldns_str_print(s, sl, "%s", buf);
+       (*d)+=16;
+       (*dl)-=16;
+       return w;
+#else
+       return -1;
+#endif
+}
+
+/** printout escaped TYPE_STR character */
+static int str_char_print(char** s, size_t* sl, uint8_t c)
+{
+       if(isprint((unsigned char)c) || c == '\t') {
+               if(c == '\"' || c == '\\')
+                       return sldns_str_print(s, sl, "\\%c", c);
+               if(*sl) {
+                       **s = (char)c;
+                       (*s)++;
+                       (*sl)--;
+               }
+               return 1;
+       }
+       return sldns_str_print(s, sl, "\\%03u", (unsigned)c);
+}
+
+int sldns_wire2str_str_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       int w = 0;
+       size_t i, len;
+       if(*dl < 1) return -1;
+       len = **d;
+       if(*dl < 1+len) return -1;
+       (*d)++;
+       (*dl)--;
+       w += sldns_str_print(s, sl, "\"");
+       for(i=0; i<len; i++)
+               w += str_char_print(s, sl, (*d)[i]);
+       w += sldns_str_print(s, sl, "\"");
+       (*d)+=len;
+       (*dl)-=len;
+       return w;
+}
+
+int sldns_wire2str_apl_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       int i, w = 0;
+       uint16_t family;
+       uint8_t negation, prefix, adflength;
+       if(*dl < 4) return -1;
+       family = sldns_read_uint16(*d);
+       prefix = (*d)[2];
+       negation = ((*d)[3] & LDNS_APL_NEGATION);
+       adflength = ((*d)[3] & LDNS_APL_MASK);
+       if(*dl < 4+(size_t)adflength) return -1;
+       if(family != LDNS_APL_IP4 && family != LDNS_APL_IP6)
+               return -1; /* unknown address family */
+       if(negation)
+               w += sldns_str_print(s, sl, "!");
+       w += sldns_str_print(s, sl, "%u:", (unsigned)family);
+       if(family == LDNS_APL_IP4) {
+               /* check if prefix <32 ? */
+               /* address is variable length 0 - 4 */
+               for(i=0; i<4; i++) {
+                       if(i > 0)
+                               w += sldns_str_print(s, sl, ".");
+                       if(i < (int)adflength)
+                               w += sldns_str_print(s, sl, "%d", (*d)[4+i]);
+                       else    w += sldns_str_print(s, sl, "0");
+               }
+       } else if(family == LDNS_APL_IP6) {
+               /* check if prefix <128 ? */
+               /* address is variable length 0 - 16 */
+               for(i=0; i<16; i++) {
+                       if(i%2 == 0 && i>0)
+                               w += sldns_str_print(s, sl, ":");
+                       if(i < (int)adflength)
+                               w += sldns_str_print(s, sl, "%02x", (*d)[4+i]);
+                       else    w += sldns_str_print(s, sl, "00");
+               }
+       }
+       w += sldns_str_print(s, sl, "/%u", (unsigned)prefix);
+       (*d) += 4+adflength;
+       (*dl) -= 4+adflength;
+       return w;
+}
+
+int sldns_wire2str_b32_ext_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       size_t datalen;
+       size_t sz;
+       if(*dl < 1) return -1;
+       datalen = (*d)[0];
+       if(*dl < 1+datalen) return -1;
+       sz = sldns_b32_ntop_calculate_size(datalen);
+       if(*sl < sz+1) {
+               (*d) += datalen+1;
+               (*dl) -= (datalen+1);
+               return (int)sz; /* out of space really, but would need buffer
+                       in order to truncate the output */
+       }
+       sldns_b32_ntop_extended_hex((*d)+1, datalen, *s, *sl);
+       (*d) += datalen+1;
+       (*dl) -= (datalen+1);
+       (*s) += sz;
+       (*sl) -= sz;
+       return (int)sz;
+}
+
+/** scan number of bytes from wire into b64 presentation format */
+static int sldns_wire2str_b64_scan_num(uint8_t** d, size_t* dl, char** s,
+       size_t* sl, size_t num)
+{
+       /* b64_ntop_calculate size includes null at the end */
+       size_t sz = sldns_b64_ntop_calculate_size(num)-1;
+       if(*sl < sz+1) {
+               (*d) += num;
+               (*dl) -= num;
+               return (int)sz; /* out of space really, but would need buffer
+                       in order to truncate the output */
+       }
+       sldns_b64_ntop(*d, num, *s, *sl);
+       (*d) += num;
+       (*dl) -= num;
+       (*s) += sz;
+       (*sl) -= sz;
+       return (int)sz;
+}
+
+int sldns_wire2str_b64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       return sldns_wire2str_b64_scan_num(d, dl, s, sl, *dl);
+}
+
+int sldns_wire2str_hex_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       return print_remainder_hex("", d, dl, s, sl);
+}
+
+int sldns_wire2str_nsec_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       uint8_t* p = *d;
+       size_t pl = *dl;
+       unsigned i, bit, window, block_len;
+       uint16_t t;
+       int w = 0;
+       
+       /* check for errors */
+       while(pl) {
+               if(pl < 2) return -1;
+               block_len = (unsigned)p[1];
+               if(pl < 2+block_len) return -1;
+               p += block_len+2;
+               pl -= block_len+2;
+       }
+
+       /* do it */
+       p = *d;
+       pl = *dl;
+       while(pl) {
+               if(pl < 2) return -1; /* cannot happen */
+               window = (unsigned)p[0];
+               block_len = (unsigned)p[1];
+               if(pl < 2+block_len) return -1; /* cannot happen */
+               p += 2;
+               for(i=0; i<block_len; i++) {
+                       if(p[i] == 0) continue;
+                       /* base type number for this octet */
+                       t = ((window)<<8) | (i << 3);
+                       for(bit=0; bit<8; bit++) {
+                               if((p[i]&(0x80>>bit))) {
+                                       if(w) w += sldns_str_print(s, sl, " ");
+                                       w += sldns_wire2str_type_print(s, sl,
+                                               t+bit);
+                               }
+                       }
+               }
+               p += block_len;
+               pl -= block_len+2;
+       }
+       (*d) += *dl;
+       (*dl) = 0;
+       return w;
+}
+
+int sldns_wire2str_nsec3_salt_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       size_t salt_len;
+       int w;
+       if(*dl < 1) return -1;
+       salt_len = (size_t)(*d)[0];
+       if(*dl < 1+salt_len) return -1;
+       (*d)++;
+       (*dl)--;
+       if(salt_len == 0) {
+               return sldns_str_print(s, sl, "-");
+       }
+       w = print_hex_buf(s, sl, *d, salt_len);
+       (*dl)-=salt_len;
+       (*d)+=salt_len;
+       return w;
+}
+
+int sldns_wire2str_cert_alg_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       sldns_lookup_table *lt;
+       int data, w;
+       if(*dl < 2) return -1;
+       data = (int)sldns_read_uint16(*d);
+       lt = sldns_lookup_by_id(sldns_cert_algorithms, data);
+       if(lt && lt->name)
+               w = sldns_str_print(s, sl, "%s", lt->name);
+       else    w = sldns_str_print(s, sl, "%d", data);
+       (*dl)-=2;
+       (*d)+=2;
+       return w;
+}
+
+int sldns_wire2str_alg_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       /* don't use algorithm mnemonics in the presentation format
+        * this kind of got sneaked into the rfc's */
+       return sldns_wire2str_int8_scan(d, dl, s, sl);
+}
+
+int sldns_wire2str_unknown_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       return sldns_wire2str_rdata_unknown_scan(d, dl, s, sl);
+}
+
+int sldns_wire2str_time_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       /* create a YYYYMMDDHHMMSS string if possible */
+       struct tm tm;
+       char date_buf[16];
+       uint32_t t;
+       memset(&tm, 0, sizeof(tm));
+       if(*dl < 4) return -1;
+       t = sldns_read_uint32(*d);
+       date_buf[15]=0;
+       if(sldns_serial_arithmitics_gmtime_r(t, time(NULL), &tm) &&
+               strftime(date_buf, 15, "%Y%m%d%H%M%S", &tm)) {
+               (*d) += 4;
+               (*dl) -= 4;
+               return sldns_str_print(s, sl, "%s", date_buf);
+       }
+       return -1;
+}
+
+static int
+loc_cm_print(char** str, size_t* sl, uint8_t mantissa, uint8_t exponent)
+{
+       int w = 0;
+       uint8_t i;
+       /* is it 0.<two digits> ? */
+       if(exponent < 2) {
+               if(exponent == 1)
+                       mantissa *= 10;
+               return sldns_str_print(str, sl, "0.%02ld", (long)mantissa);
+       }
+       /* always <digit><string of zeros> */
+       w += sldns_str_print(str, sl, "%d", (int)mantissa);
+       for(i=0; i<exponent-2; i++)
+               w += sldns_str_print(str, sl, "0");
+       return w;
+}
+
+int sldns_wire2str_loc_scan(uint8_t** d, size_t* dl, char** str, size_t* sl)
+{
+       /* we could do checking (ie degrees < 90 etc)? */
+       uint8_t version;
+       uint8_t size;
+       uint8_t horizontal_precision;
+       uint8_t vertical_precision;
+       uint32_t longitude;
+       uint32_t latitude;
+       uint32_t altitude;
+       char northerness;
+       char easterness;
+       uint32_t h;
+       uint32_t m;
+       double s;
+       uint32_t equator = (uint32_t)1 << 31; /* 2**31 */
+       int w = 0;
+
+       if(*dl < 16) return -1;
+       version = (*d)[0];
+       if(version != 0)
+               return sldns_wire2str_hex_scan(d, dl, str, sl);
+       size = (*d)[1];
+       horizontal_precision = (*d)[2];
+       vertical_precision = (*d)[3];
+
+       latitude = sldns_read_uint32((*d)+4);
+       longitude = sldns_read_uint32((*d)+8);
+       altitude = sldns_read_uint32((*d)+12);
+
+       if (latitude > equator) {
+               northerness = 'N';
+               latitude = latitude - equator;
+       } else {
+               northerness = 'S';
+               latitude = equator - latitude;
+       }
+       h = latitude / (1000 * 60 * 60);
+       latitude = latitude % (1000 * 60 * 60);
+       m = latitude / (1000 * 60);
+       latitude = latitude % (1000 * 60);
+       s = (double) latitude / 1000.0;
+       w += sldns_str_print(str, sl, "%02u %02u %06.3f %c ",
+               h, m, s, northerness);
+
+       if (longitude > equator) {
+               easterness = 'E';
+               longitude = longitude - equator;
+       } else {
+               easterness = 'W';
+               longitude = equator - longitude;
+       }
+       h = longitude / (1000 * 60 * 60);
+       longitude = longitude % (1000 * 60 * 60);
+       m = longitude / (1000 * 60);
+       longitude = longitude % (1000 * 60);
+       s = (double) longitude / (1000.0);
+       w += sldns_str_print(str, sl, "%02u %02u %06.3f %c ",
+               h, m, s, easterness);
+
+       s = ((double) altitude) / 100;
+       s -= 100000;
+
+       if(altitude%100 != 0)
+               w += sldns_str_print(str, sl, "%.2f", s);
+       else
+               w += sldns_str_print(str, sl, "%.0f", s);
+
+       w += sldns_str_print(str, sl, "m ");
+
+       w += loc_cm_print(str, sl, (size & 0xf0) >> 4, size & 0x0f);
+       w += sldns_str_print(str, sl, "m ");
+
+       w += loc_cm_print(str, sl, (horizontal_precision & 0xf0) >> 4,
+               horizontal_precision & 0x0f);
+       w += sldns_str_print(str, sl, "m ");
+
+       w += loc_cm_print(str, sl, (vertical_precision & 0xf0) >> 4,
+               vertical_precision & 0x0f);
+       w += sldns_str_print(str, sl, "m");
+
+       (*d)+=16;
+       (*dl)-=16;
+       return w;
+}
+
+int sldns_wire2str_wks_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       /* protocol, followed by bitmap of services */
+       const char* proto_name = NULL;
+       struct protoent *protocol;
+       struct servent *service;
+       uint8_t protocol_nr;
+       int bit, port, w = 0;
+       size_t i;
+       /* we cannot print with strings because they
+        * are not portable, the presentation format may
+        * not be able to be read in on another computer.  */
+       int print_symbols = 0;
+
+       /* protocol */
+       if(*dl < 1) return -1;
+       protocol_nr = (*d)[0];
+       (*d)++;
+       (*dl)--;
+       protocol = getprotobynumber((int)protocol_nr);
+       if(protocol && (protocol->p_name != NULL)) {
+               w += sldns_str_print(s, sl, "%s", protocol->p_name);
+               proto_name = protocol->p_name;
+       } else  {
+               w += sldns_str_print(s, sl, "%u", (unsigned)protocol_nr);
+       }
+
+       for(i=0; i<*dl; i++) {
+               if((*d)[i] == 0)
+                       continue;
+               for(bit=0; bit<8; bit++) {
+                       if(!(((*d)[i])&(0x80>>bit)))
+                               continue;
+                       port = (int)i*8 + bit;
+
+                       if(!print_symbols)
+                               service = NULL;
+                       else
+                               service = getservbyport(
+                                       (int)htons((uint16_t)port), proto_name);
+                       if(service && service->s_name)
+                               w += sldns_str_print(s, sl, " %s",
+                                       service->s_name);
+                       else    w += sldns_str_print(s, sl, " %u",
+                                       (unsigned)port);
+               }
+       }
+
+#ifdef HAVE_ENDSERVENT
+       endservent();
+#endif
+#ifdef HAVE_ENDPROTOENT
+        endprotoent();
+#endif
+       (*d) += *dl;
+       (*dl) = 0;
+       return w;
+}
+
+int sldns_wire2str_nsap_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       return print_remainder_hex("0x", d, dl, s, sl);
+}
+
+int sldns_wire2str_atma_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       return print_remainder_hex("", d, dl, s, sl);
+}
+
+/* internal scan routine that can modify arguments on failure */
+static int sldns_wire2str_ipseckey_scan_internal(uint8_t** d, size_t* dl,
+       char** s, size_t* sl, uint8_t* pkt, size_t pktlen)
+{
+       /* http://www.ietf.org/internet-drafts/draft-ietf-ipseckey-rr-12.txt*/
+       uint8_t precedence, gateway_type, algorithm;
+       int w = 0;
+
+       if(*dl < 3) return -1;
+       precedence = (*d)[0];
+       gateway_type = (*d)[1];
+       algorithm = (*d)[2];
+       if(gateway_type > 3)
+               return -1; /* unknown */
+       (*d)+=3;
+       (*dl)-=3;
+       w += sldns_str_print(s, sl, "%d %d %d ",
+               (int)precedence, (int)gateway_type, (int)algorithm);
+
+       switch(gateway_type) {
+       case 0: /* no gateway */
+               w += sldns_str_print(s, sl, ".");
+               break;
+       case 1: /* ip4 */
+               w += sldns_wire2str_a_scan(d, dl, s, sl);
+               break;
+       case 2: /* ip6 */
+               w += sldns_wire2str_aaaa_scan(d, dl, s, sl);
+               break;
+       case 3: /* dname */
+               w += sldns_wire2str_dname_scan(d, dl, s, sl, pkt, pktlen);
+               break;
+       default: /* unknown */
+               return -1;
+       }
+
+       if(*dl < 1)
+               return -1;
+       w += sldns_str_print(s, sl, " ");
+       w += sldns_wire2str_b64_scan_num(d, dl, s, sl, *dl);
+       return w;
+}
+
+int sldns_wire2str_ipseckey_scan(uint8_t** d, size_t* dl, char** s, size_t* sl,
+       uint8_t* pkt, size_t pktlen)
+{
+       uint8_t* od = *d;
+       char* os = *s;
+       size_t odl = *dl, osl = *sl;
+       int w=sldns_wire2str_ipseckey_scan_internal(d, dl, s, sl, pkt, pktlen);
+       if(w == -1) {
+               *d = od;
+               *s = os;
+               *dl = odl;
+               *sl = osl;
+               return -1;
+       }
+       return w;
+}
+
+int sldns_wire2str_hip_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       int w;
+       uint8_t algo, hitlen;
+       uint16_t pklen;
+
+       /* read lengths */
+       if(*dl < 4)
+               return -1;
+       hitlen = (*d)[0];
+       algo = (*d)[1];
+       pklen = sldns_read_uint16((*d)+2);
+       if(*dl < (size_t)4 + (size_t)hitlen + (size_t)pklen)
+               return -1;
+
+       /* write: algo hit pubkey */
+       w = sldns_str_print(s, sl, "%u ", (unsigned)algo);
+       w += print_hex_buf(s, sl, (*d)+4, hitlen);
+       w += sldns_str_print(s, sl, " ");
+       (*d)+=4+hitlen;
+       (*dl)-= (4+hitlen);
+       w += sldns_wire2str_b64_scan_num(d, dl, s, sl, pklen);
+       return w;
+}
+
+int sldns_wire2str_int16_data_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       uint16_t n;
+       if(*dl < 2)
+               return -1;
+       n = sldns_read_uint16(*d);
+       if(*dl < 2+(size_t)n)
+               return -1;
+       (*d)+=2;
+       (*dl)-=2;
+       return sldns_wire2str_b64_scan_num(d, dl, s, sl, n);
+}
+
+int sldns_wire2str_nsec3_next_owner_scan(uint8_t** d, size_t* dl, char** s,
+       size_t* sl)
+{
+       return sldns_wire2str_b32_ext_scan(d, dl, s, sl);
+}
+
+int sldns_wire2str_ilnp64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       int w;
+       if(*dl < 8)
+               return -1;
+       w = sldns_str_print(s, sl, "%.4x:%.4x:%.4x:%.4x",
+               sldns_read_uint16(*d), sldns_read_uint16((*d)+2),
+               sldns_read_uint16((*d)+4), sldns_read_uint16((*d)+6));
+       (*d)+=8;
+       (*dl)-=8;
+       return w;
+}
+
+int sldns_wire2str_eui48_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       int w;
+       if(*dl < 6)
+               return -1;
+       w = sldns_str_print(s, sl, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
+               (*d)[0], (*d)[1], (*d)[2], (*d)[3], (*d)[4], (*d)[5]);
+       (*d)+=6;
+       (*dl)-=6;
+       return w;
+}
+
+int sldns_wire2str_eui64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       int w;
+       if(*dl < 8)
+               return -1;
+       w = sldns_str_print(s, sl, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
+               (*d)[0], (*d)[1], (*d)[2], (*d)[3], (*d)[4], (*d)[5],
+               (*d)[6], (*d)[7]);
+       (*d)+=8;
+       (*dl)-=8;
+       return w;
+}
+
+int sldns_wire2str_tag_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       size_t i, n;
+       int w = 0;
+       if(*dl < 1)
+               return -1;
+       n = (size_t)((*d)[0]);
+       if(*dl < 1+n)
+               return -1;
+       for(i=0; i<n; i++)
+               if(!isalnum((unsigned char)(*d)[i]))
+                       return -1;
+       for(i=0; i<n; i++)
+               w += sldns_str_print(s, sl, "%c", (char)(*d)[i]);
+       (*d)+=n+1;
+       (*dl)-=(n+1);
+       return w;
+}
+
+int sldns_wire2str_long_str_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+       size_t i;
+       int w = 0;
+       w += sldns_str_print(s, sl, "\"");
+       for(i=0; i<*dl; i++)
+               w += str_char_print(s, sl, (*d)[i]);
+       w += sldns_str_print(s, sl, "\"");
+       (*d)+=*dl;
+       (*dl)=0;
+       return w;
+}
+
+int sldns_wire2str_edns_llq_print(char** s, size_t* sl, uint8_t* data,
+       size_t len)
+{
+       /* LLQ constants */
+       const char* llq_errors[] = {"NO-ERROR", "SERV-FULL", "STATIC",
+               "FORMAT-ERR", "NO-SUCH-LLQ", "BAD-VERS", "UNKNOWN_ERR"};
+       const unsigned int llq_errors_num = 7;
+       const char* llq_opcodes[] = {"LLQ-SETUP", "LLQ-REFRESH", "LLQ-EVENT"};
+       const unsigned int llq_opcodes_num = 3;
+       uint16_t version, llq_opcode, error_code;
+       uint64_t llq_id;
+       uint32_t lease_life; /* Requested or granted life of LLQ, in seconds */
+       int w = 0;
+
+       /* read the record */
+       if(len != 18) {
+               w += sldns_str_print(s, sl, "malformed LLQ ");
+               w += print_hex_buf(s, sl, data, len);
+               return w;
+       }
+       version = sldns_read_uint16(data);
+       llq_opcode = sldns_read_uint16(data+2);
+       error_code = sldns_read_uint16(data+4);
+       memmove(&llq_id, data+6, sizeof(llq_id));
+       lease_life = sldns_read_uint32(data+14);
+
+       /* print it */
+       w += sldns_str_print(s, sl, "v%d ", (int)version);
+       if(llq_opcode < llq_opcodes_num)
+               w += sldns_str_print(s, sl, "%s", llq_opcodes[llq_opcode]);
+       else    w += sldns_str_print(s, sl, "opcode %d", (int)llq_opcode);
+       if(error_code < llq_errors_num)
+               w += sldns_str_print(s, sl, " %s", llq_errors[error_code]);
+       else    w += sldns_str_print(s, sl, " error %d", (int)error_code);
+#ifndef USE_WINSOCK
+       w += sldns_str_print(s, sl, " id %llx lease-life %lu",
+               (unsigned long long)llq_id, (unsigned long)lease_life);
+#else
+       w += sldns_str_print(s, sl, " id %I64x lease-life %lu",
+               (unsigned long long)llq_id, (unsigned long)lease_life);
+#endif
+       return w;
+}
+
+int sldns_wire2str_edns_ul_print(char** s, size_t* sl, uint8_t* data,
+       size_t len)
+{
+       uint32_t lease;
+       int w = 0;
+       if(len != 4) {
+               w += sldns_str_print(s, sl, "malformed UL ");
+               w += print_hex_buf(s, sl, data, len);
+               return w;
+       }
+       lease = sldns_read_uint32(data);
+       w += sldns_str_print(s, sl, "lease %lu", (unsigned long)lease);
+       return w;
+}
+
+int sldns_wire2str_edns_nsid_print(char** s, size_t* sl, uint8_t* data,
+       size_t len)
+{
+       int w = 0;
+       size_t i, printed=0;
+       w += print_hex_buf(s, sl, data, len);
+       for(i=0; i<len; i++) {
+               if(isprint((unsigned char)data[i]) || data[i] == '\t') {
+                       if(!printed) {
+                               w += sldns_str_print(s, sl, " (");
+                               printed = 1;
+                       }
+                       w += sldns_str_print(s, sl, "%c", (char)data[i]);
+               }
+       }
+       if(printed)
+               w += sldns_str_print(s, sl, ")");
+       return w;
+}
+
+int sldns_wire2str_edns_dau_print(char** s, size_t* sl, uint8_t* data,
+       size_t len)
+{
+       sldns_lookup_table *lt;
+       size_t i;
+       int w = 0;
+       for(i=0; i<len; i++) {
+               lt = sldns_lookup_by_id(sldns_algorithms, (int)data[i]);
+               if(lt && lt->name)
+                       w += sldns_str_print(s, sl, " %s", lt->name);
+               else    w += sldns_str_print(s, sl, " %d", (int)data[i]);
+       }
+       return w;
+}
+
+int sldns_wire2str_edns_dhu_print(char** s, size_t* sl, uint8_t* data,
+       size_t len)
+{
+       sldns_lookup_table *lt;
+       size_t i;
+       int w = 0;
+       for(i=0; i<len; i++) {
+               lt = sldns_lookup_by_id(sldns_hashes, (int)data[i]);
+               if(lt && lt->name)
+                       w += sldns_str_print(s, sl, " %s", lt->name);
+               else    w += sldns_str_print(s, sl, " %d", (int)data[i]);
+       }
+       return w;
+}
+
+int sldns_wire2str_edns_n3u_print(char** s, size_t* sl, uint8_t* data,
+       size_t len)
+{
+       size_t i;
+       int w = 0;
+       for(i=0; i<len; i++) {
+               if(data[i] == 1)
+                       w += sldns_str_print(s, sl, " SHA1");
+               else    w += sldns_str_print(s, sl, " %d", (int)data[i]);
+       }
+       return w;
+}
+
+int sldns_wire2str_edns_subnet_print(char** s, size_t* sl, uint8_t* data,
+       size_t len)
+{
+       int w = 0;
+       uint16_t family;
+       uint8_t source, scope;
+       if(len < 4) {
+               w += sldns_str_print(s, sl, "malformed subnet ");
+               w += print_hex_buf(s, sl, data, len);
+               return w;
+       }
+       family = sldns_read_uint16(data);
+       source = data[2];
+       scope = data[3];
+       if(family == 1) {
+               /* IP4 */
+               char buf[64];
+               uint8_t ip4[4];
+               memset(ip4, 0, sizeof(ip4));
+               if(len-4 > 4) {
+                       w += sldns_str_print(s, sl, "trailingdata:");
+                       w += print_hex_buf(s, sl, data+4+4, len-4-4);
+                       w += sldns_str_print(s, sl, " ");
+                       len = 4+4;
+               }
+               memmove(ip4, data+4, len-4);
+               if(!inet_ntop(AF_INET, ip4, buf, (socklen_t)sizeof(buf))) {
+                       w += sldns_str_print(s, sl, "ip4ntoperror ");
+                       w += print_hex_buf(s, sl, data+4+4, len-4-4);
+               } else {
+                       w += sldns_str_print(s, sl, "%s", buf);
+               }
+       } else if(family == 2) {
+               /* IP6 */
+               char buf[64];
+               uint8_t ip6[16];
+               memset(ip6, 0, sizeof(ip6));
+               if(len-4 > 16) {
+                       w += sldns_str_print(s, sl, "trailingdata:");
+                       w += print_hex_buf(s, sl, data+4+16, len-4-16);
+                       w += sldns_str_print(s, sl, " ");
+                       len = 4+16;
+               }
+               memmove(ip6, data+4, len-4);
+#ifdef AF_INET6
+               if(!inet_ntop(AF_INET6, ip6, buf, (socklen_t)sizeof(buf))) {
+                       w += sldns_str_print(s, sl, "ip6ntoperror ");
+                       w += print_hex_buf(s, sl, data+4+4, len-4-4);
+               } else {
+                       w += sldns_str_print(s, sl, "%s", buf);
+               }
+#else
+               w += print_hex_buf(s, sl, data+4+4, len-4-4);
+#endif
+       } else {
+               /* unknown */
+               w += sldns_str_print(s, sl, "family %d ",
+                       (int)family);
+               w += print_hex_buf(s, sl, data, len);
+       }
+       w += sldns_str_print(s, sl, "/%d scope /%d", (int)source, (int)scope);
+       return w;
+}
+
+int sldns_wire2str_edns_option_print(char** s, size_t* sl,
+       uint16_t option_code, uint8_t* optdata, size_t optlen)
+{
+       int w = 0;
+       w += sldns_wire2str_edns_option_code_print(s, sl, option_code);
+       w += sldns_str_print(s, sl, ": ");
+       switch(option_code) {
+       case LDNS_EDNS_LLQ:
+               w += sldns_wire2str_edns_llq_print(s, sl, optdata, optlen);
+               break;
+       case LDNS_EDNS_UL:
+               w += sldns_wire2str_edns_ul_print(s, sl, optdata, optlen);
+               break;
+       case LDNS_EDNS_NSID:
+               w += sldns_wire2str_edns_nsid_print(s, sl, optdata, optlen);
+               break;
+       case LDNS_EDNS_DAU:
+               w += sldns_wire2str_edns_dau_print(s, sl, optdata, optlen);
+               break;
+       case LDNS_EDNS_DHU:
+               w += sldns_wire2str_edns_dhu_print(s, sl, optdata, optlen);
+               break;
+       case LDNS_EDNS_N3U:
+               w += sldns_wire2str_edns_n3u_print(s, sl, optdata, optlen);
+               break;
+       case LDNS_EDNS_CLIENT_SUBNET:
+               w += sldns_wire2str_edns_subnet_print(s, sl, optdata, optlen);
+               break;
+       default:
+               /* unknown option code */
+               w += print_hex_buf(s, sl, optdata, optlen);
+               break;
+       }
+       return w;
+}
+
+/** print the edns options to string */
+static int
+print_edns_opts(char** s, size_t* sl, uint8_t* rdata, size_t rdatalen)
+{
+       uint16_t option_code, option_len;
+       int w = 0;
+       while(rdatalen > 0) {
+               /* option name */
+               if(rdatalen < 4) {
+                       w += sldns_str_print(s, sl, " ; malformed: ");
+                       w += print_hex_buf(s, sl, rdata, rdatalen);
+                       return w;
+               }
+               option_code = sldns_read_uint16(rdata);
+               option_len = sldns_read_uint16(rdata+2);
+               rdata += 4;
+               rdatalen -= 4;
+
+               /* option value */
+               if(rdatalen < (size_t)option_len) {
+                       w += sldns_str_print(s, sl, " ; malformed ");
+                       w += sldns_wire2str_edns_option_code_print(s, sl,
+                               option_code);
+                       w += sldns_str_print(s, sl, ": ");
+                       w += print_hex_buf(s, sl, rdata, rdatalen);
+                       return w;
+               }
+               w += sldns_str_print(s, sl, " ; ");
+               w += sldns_wire2str_edns_option_print(s, sl, option_code,
+                       rdata, option_len);
+               rdata += option_len;
+               rdatalen -= option_len;
+       }
+       return w;
+}
+
+int sldns_wire2str_edns_scan(uint8_t** data, size_t* data_len, char** str,
+        size_t* str_len, uint8_t* pkt, size_t pktlen)
+{
+       int w = 0;
+       uint8_t ext_rcode, edns_version;
+       uint16_t udpsize, edns_bits, rdatalen;
+       w += sldns_str_print(str, str_len, "; EDNS:");
+
+       /* some input checks, domain name */
+       if(*data_len < 1+10)
+               return w + print_remainder_hex("Error malformed 0x",
+                       data, data_len, str, str_len);
+       if(*data[0] != 0) {
+               return w + print_remainder_hex("Error nonrootdname 0x",
+                       data, data_len, str, str_len);
+       }
+       (*data)++;
+       (*data_len)--;
+
+       /* check type and read fixed contents */
+       if(sldns_read_uint16((*data)) != LDNS_RR_TYPE_OPT) {
+               return w + print_remainder_hex("Error nottypeOPT 0x",
+                       data, data_len, str, str_len);
+       }
+       udpsize = sldns_read_uint16((*data)+2);
+       ext_rcode = (*data)[4];
+       edns_version = (*data)[5];
+       edns_bits = sldns_read_uint16((*data)+6);
+       rdatalen = sldns_read_uint16((*data)+8);
+       (*data)+=10;
+       (*data_len)-=10;
+
+       w += sldns_str_print(str, str_len, " version: %u;",
+               (unsigned)edns_version);
+       w += sldns_str_print(str, str_len, " flags:");
+       if((edns_bits & LDNS_EDNS_MASK_DO_BIT))
+               w += sldns_str_print(str, str_len, " do");
+       /* the extended rcode is the value set, shifted four bits,
+        * and or'd with the original rcode */
+       if(ext_rcode) {
+               int rc = ((int)ext_rcode)<<4;
+               if(pkt && pktlen >= LDNS_HEADER_SIZE)
+                       rc |= LDNS_RCODE_WIRE(pkt);
+               w += sldns_str_print(str, str_len, " ; ext-rcode: %d", rc);
+       }
+       w += sldns_str_print(str, str_len, " ; udp: %u", (unsigned)udpsize);
+
+       if(rdatalen) {
+               if(*data_len < rdatalen) {
+                       w += sldns_str_print(str, str_len,
+                               " ; Error EDNS rdata too short; ");
+                       rdatalen = *data_len;
+               }
+               w += print_edns_opts(str, str_len, *data, rdatalen);
+               (*data) += rdatalen;
+               (*data_len) -= rdatalen;
+       }
+       w += sldns_str_print(str, str_len, "\n");
+       return w;
+}
diff --git a/sldns/wire2str.h b/sldns/wire2str.h
new file mode 100644 (file)
index 0000000..67f5435
--- /dev/null
@@ -0,0 +1,984 @@
+/**
+ * wire2str.h -  txt presentation of RRs
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Contains functions to translate the wireformat to text
+ * representation, as well as functions to print them.
+ */
+
+#ifndef LDNS_WIRE2STR_H
+#define LDNS_WIRE2STR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct sldns_struct_lookup_table;
+
+/* lookup tables for standard DNS stuff  */
+/** Taken from RFC 2535, section 7.  */
+extern struct sldns_struct_lookup_table* sldns_algorithms;
+/** DS record hash algorithms */
+extern struct sldns_struct_lookup_table* sldns_hashes;
+/** Taken from RFC 2538, section 2.1.  */
+extern struct sldns_struct_lookup_table* sldns_cert_algorithms;
+/** Response codes */
+extern struct sldns_struct_lookup_table* sldns_rcodes;
+/** Operation codes */
+extern struct sldns_struct_lookup_table* sldns_opcodes;
+/** EDNS flags */
+extern struct sldns_struct_lookup_table* sldns_edns_flags;
+/** EDNS option codes */
+extern struct sldns_struct_lookup_table* sldns_edns_options;
+/** error string from wireparse */
+extern struct sldns_struct_lookup_table* sldns_wireparse_errors;
+
+/**
+ * Convert wireformat packet to a string representation
+ * @param data: wireformat packet data (starting at ID bytes).
+ * @param len: length of packet.
+ * @return string(malloced) or NULL on failure.
+ */
+char* sldns_wire2str_pkt(uint8_t* data, size_t len);
+
+/**
+ * Convert wireformat RR to a string representation.
+ * @param rr: the wireformat RR, in uncompressed form.  Starts at the domain
+ *     name start, ends with the rdata of the RR.
+ * @param len: length of the rr wireformat.
+ * @return string(malloced) or NULL on failure.
+ */
+char* sldns_wire2str_rr(uint8_t* rr, size_t len);
+
+/**
+ * Conver wire dname to a string.
+ * @param dname: the dname in uncompressed wireformat.
+ * @param dname_len: length of the dname.
+ * @return string or NULL on failure.
+ */
+char* sldns_wire2str_dname(uint8_t* dname, size_t dname_len);
+
+/**
+ * Convert wire RR type to a string, 'MX', 'TYPE1234'...
+ * @param rrtype: the RR type in host order.
+ * @return malloced string with the RR type or NULL on malloc failure.
+ */
+char* sldns_wire2str_type(uint16_t rrtype);
+
+/**
+ * Convert wire RR class to a string, 'IN', 'CLASS1'.
+ * @param rrclass: the RR class in host order.
+ * @return malloced string with the RR class or NULL on malloc failure.
+ */
+char* sldns_wire2str_class(uint16_t rrclass);
+
+/**
+ * Convert wire packet rcode to a string, 'NOERROR', 'NXDOMAIN'...
+ * @param rcode: as integer, host order
+ * @return malloced string with the rcode or NULL on malloc failure.
+ */
+char* sldns_wire2str_rcode(int rcode);
+
+/**
+ * Print to string, move string along for next content. With va_list.
+ * @param str: string buffer.  Adjusted at end to after the output.
+ * @param slen: length of the string buffer.  Adjusted at end.
+ * @param format: printf format string.
+ * @param args: arguments for printf.
+ * @return number of characters needed. Can be larger than slen.
+ */
+int sldns_str_vprint(char** str, size_t* slen, const char* format, va_list args);
+
+/**
+ * Print to string, move string along for next content.
+ * @param str: string buffer.  Adjusted at end to after the output.
+ * @param slen: length of the string buffer.  Adjusted at end.
+ * @param format: printf format string and arguments for it.
+ * @return number of characters needed. Can be larger than slen.
+ */
+int sldns_str_print(char** str, size_t* slen, const char* format, ...)
+       ATTR_FORMAT(printf, 3, 4);
+
+/**
+ * Convert wireformat packet to a string representation with user buffer
+ * It appends every RR with default comments.
+ * For more formatter options use the function: TBD(TODO)
+ * @param data: wireformat packet data (starting at ID bytes).
+ * @param data_len: length of packet.
+ * @param str: the string buffer for the output.
+ *     If you pass NULL as the str the return value of the function is
+ *     the str_len you need for the entire packet.  It does not include
+ *     the 0 byte at the end.
+ * @param str_len: the size of the string buffer.  If more is needed, it'll
+ *     silently truncate the output to fit in the buffer.
+ * @return the number of characters for this element, excluding zerobyte.
+ *     Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_pkt_buf(uint8_t* data, size_t data_len, char* str,
+       size_t str_len);
+
+/**
+ * Scan wireformat packet to a string representation with user buffer
+ * It appends every RR with default comments.
+ * For more formatter options use the function: TBD(TODO)
+ * @param data: wireformat packet data (starting at ID bytes).
+ * @param data_len: length of packet.
+ * @param str: the string buffer for the output.
+ * @param str_len: the size of the string buffer.
+ * @return number of characters for string.
+ * returns the number of characters that are needed (except terminating null),
+ * so it may return a value larger than str_len.
+ * On error you get less output (i.e. shorter output in str (null terminated))
+ * On exit the data, data_len, str and str_len values are adjusted to move them
+ * from their original position along the input and output for the content
+ * that has been consumed (and produced) by this function.  If the end of the
+ * output string is reached, *str_len is set to 0.  The output string is null
+ * terminated (shortening the output if necessary).  If the end of the input
+ * is reached *data_len is set to 0.
+ */
+int sldns_wire2str_pkt_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat rr to string, with user buffers.  It shifts the arguments
+ * to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rr_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Scan wireformat question rr to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rrquestion_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Scan wireformat RR to string in unknown RR format, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rr_unknown_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Print to string the RR-information comment in default format,
+ * with user buffers.  Moves string along.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param rr: wireformat data.
+ * @param rrlen: length of data buffer.
+ * @param dname_off: offset in buffer behind owner dname, the compressed size
+ *     of the owner name.
+ * @param rrtype: type of the RR, host format.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rr_comment_print(char** str, size_t* str_len, uint8_t* rr,
+       size_t rrlen, size_t dname_off, uint16_t rrtype);
+
+/**
+ * Scan wireformat packet header to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_header_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat rdata to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.  The length of the rdata in the
+ *     buffer.  The rdatalen itself has already been scanned, the data
+ *     points to the rdata after the rdatalen.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param rrtype: RR type of Rdata, host format.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rdata_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len, uint16_t rrtype, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Scan wireformat rdata to string in unknown format, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer, the length of the rdata in buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rdata_unknown_scan(uint8_t** data, size_t* data_len,
+       char** str, size_t* str_len);
+
+/**
+ * Scan wireformat domain name to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_dname_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Scan wireformat rr type to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_type_scan(uint8_t** data, size_t* data_len, char** str,
+        size_t* str_len);
+
+/**
+ * Scan wireformat rr class to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_class_scan(uint8_t** data, size_t* data_len, char** str,
+        size_t* str_len);
+
+/**
+ * Scan wireformat rr ttl to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_ttl_scan(uint8_t** data, size_t* data_len, char** str,
+        size_t* str_len);
+
+
+/**
+ * Print host format rr type to string.  Moves string along, user buffers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param rrtype: host format rr type.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_type_print(char** str, size_t* str_len, uint16_t rrtype);
+
+/**
+ * Print host format rr class to string.  Moves string along, user buffers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param rrclass: host format rr class.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_class_print(char** str, size_t* str_len, uint16_t rrclass);
+
+/**
+ * Print host format rcode to string.  Moves string along, user buffers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param rcode: host format rcode number.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rcode_print(char** str, size_t* str_len, int rcode);
+
+/**
+ * Print host format opcode to string.  Moves string along, user buffers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param opcode: host format opcode number.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_opcode_print(char** str, size_t* str_len, int opcode);
+
+/**
+ * Print host format EDNS0 option to string.  Moves string along, user buffers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param opcode: host format option number.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_option_code_print(char** str, size_t* str_len,
+       uint16_t opcode);
+
+/**
+ * Convert RR to string presentation format, on one line.  User buffer.
+ * @param rr: wireformat RR data
+ * @param rr_len: length of the rr wire data.
+ * @param str: the string buffer to write to.
+ *     If you pass NULL as the str, the return value of the function is
+ *     the str_len you need for the entire packet.  It does not include
+ *     the 0 byte at the end.
+ * @param str_len: the size of the string buffer.  If more is needed, it'll
+ *     silently truncate the output to fit in the buffer.
+ * @return the number of characters for this element, excluding zerobyte.
+ *     Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_rr_buf(uint8_t* rr, size_t rr_len, char* str,
+       size_t str_len);
+
+/**
+ * 3597 printout of an RR in unknown rr format.
+ * There are more format and comment options available for printout
+ * with the function: TBD(TODO)
+ * @param rr: wireformat RR data
+ * @param rr_len: length of the rr wire data.
+ * @param str: the string buffer to write to.
+ *     If you pass NULL as the str, the return value of the function is
+ *     the str_len you need for the entire rr.  It does not include
+ *     the 0 byte at the end.
+ * @param str_len: the size of the string buffer.  If more is needed, it'll
+ *     silently truncate the output to fit in the buffer.
+ * @return the number of characters for this element, excluding zerobyte.
+ *     Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_rr_unknown_buf(uint8_t* rr, size_t rr_len, char* str,
+       size_t str_len);
+
+/**
+ * This creates the comment to print after the RR. ; keytag=... , and other
+ * basic comments for RRs.
+ * There are more format and comment options available for printout
+ * with the function: TBD(TODO)
+ * @param rr: wireformat RR data
+ * @param rr_len: length of the rr wire data.
+ * @param dname_len: length of the dname in front of the RR.
+ * @param str: the string buffer to write to.
+ *     If you pass NULL as the str, the return value of the function is
+ *     the str_len you need for the entire comment.  It does not include
+ *     the 0 byte at the end.
+ * @param str_len: the size of the string buffer.  If more is needed, it'll
+ *     silently truncate the output to fit in the buffer.
+ * @return the number of characters for this element, excluding zerobyte.
+ *     Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_rr_comment_buf(uint8_t* rr, size_t rr_len, size_t dname_len,
+       char* str, size_t str_len);
+
+/**
+ * Convert RDATA to string presentation format, on one line.  User buffer.
+ * @param rdata: wireformat rdata part of an RR.
+ * @param rdata_len: length of the rr wire data.
+ * @param str: the string buffer to write to.
+ *     If you pass NULL as the str, the return value of the function is
+ *     the str_len you need for the entire packet.  It does not include
+ *     the 0 byte at the end.
+ * @param str_len: the size of the string buffer.  If more is needed, it'll
+ *     silently truncate the output to fit in the buffer.
+ * @param rrtype: rr type of the data
+ * @return the number of characters for this element, excluding zerobyte.
+ *     Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_rdata_buf(uint8_t* rdata, size_t rdata_len, char* str,
+       size_t str_len, uint16_t rrtype);
+
+/**
+ * Convert wire RR type to a string, 'MX', 'TYPE12'.  With user buffer.
+ * @param rrtype: the RR type in host order.
+ * @param str: the string to write to.
+ * @param len: length of str.
+ * @return the number of characters for this element, excluding zerobyte.
+ *     Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_type_buf(uint16_t rrtype, char* str, size_t len);
+
+/**
+ * Convert wire RR class to a string, 'IN', 'CLASS12'.  With user buffer.
+ * @param rrclass: the RR class in host order.
+ * @param str: the string to write to.
+ * @param len: length of str.
+ * @return the number of characters for this element, excluding zerobyte.
+ *     Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_class_buf(uint16_t rrclass, char* str, size_t len);
+
+/**
+ * Convert wire RR rcode to a string, 'NOERROR', 'NXDOMAIN'.  With user buffer.
+ * @param rcode: rcode as integer in host order
+ * @param str: the string to write to.
+ * @param len: length of str.
+ * @return the number of characters for this element, excluding zerobyte.
+ *     Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_rcode_buf(int rcode, char* str, size_t len);
+
+/**
+ * Convert wire dname to a string, "example.com.".  With user buffer.
+ * @param dname: the dname in uncompressed wireformat.
+ * @param dname_len: length of the dname.
+ * @param str: the string to write to.
+ * @param len: length of string.
+ * @return the number of characters for this element, excluding zerobyte.
+ *     Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_dname_buf(uint8_t* dname, size_t dname_len, char* str,
+       size_t len);
+
+/**
+ * Scan wireformat rdf field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param rdftype: the type of the rdata field, enum sldns_rdf_type.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_rdf_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len, int rdftype, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Scan wireformat int8 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_int8_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat int16 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_int16_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat int32 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_int32_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat period field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_period_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat tsigtime field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_tsigtime_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat ip4 A field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_a_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat ip6 AAAA field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_aaaa_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat str field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_str_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat apl field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_apl_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat b32_ext field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_b32_ext_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat b64 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_b64_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat hex field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_hex_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat nsec bitmap field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_nsec_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat nsec3_salt field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_nsec3_salt_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat cert_alg field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_cert_alg_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat alg field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_alg_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat type unknown field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_unknown_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat time field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_time_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat LOC field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_loc_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat WKS field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_wks_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat NSAP field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_nsap_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat ATMA field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_atma_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat IPSECKEY field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_ipseckey_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Scan wireformat HIP (algo, HIT, pubkey) field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_hip_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat int16_data field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_int16_data_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat nsec3_next_owner field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_nsec3_next_owner_scan(uint8_t** data, size_t* data_len,
+       char** str, size_t* str_len);
+
+/**
+ * Scan wireformat ILNP64 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_ilnp64_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat EUI48 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_eui48_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat EUI64 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_eui64_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat TAG field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_tag_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Scan wireformat long_str field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ *     Can return -1 on failure.
+ */
+int sldns_wire2str_long_str_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len);
+
+/**
+ * Print EDNS LLQ option data to string.  User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_llq_print(char** str, size_t* str_len,
+       uint8_t* option_data, size_t option_len);
+
+/**
+ * Print EDNS UL option data to string.  User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_ul_print(char** str, size_t* str_len,
+       uint8_t* option_data, size_t option_len);
+
+/**
+ * Print EDNS NSID option data to string.  User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_nsid_print(char** str, size_t* str_len,
+       uint8_t* option_data, size_t option_len);
+
+/**
+ * Print EDNS DAU option data to string.  User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_dau_print(char** str, size_t* str_len,
+       uint8_t* option_data, size_t option_len);
+
+/**
+ * Print EDNS DHU option data to string.  User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_dhu_print(char** str, size_t* str_len,
+       uint8_t* option_data, size_t option_len);
+
+/**
+ * Print EDNS N3U option data to string.  User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_n3u_print(char** str, size_t* str_len,
+       uint8_t* option_data, size_t option_len);
+
+/**
+ * Print EDNS SUBNET option data to string. User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_subnet_print(char** str, size_t* str_len,
+       uint8_t* option_data, size_t option_len);
+
+/**
+ * Print an EDNS option as OPT: VALUE.  User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_code: host format EDNS option code.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_option_print(char** str, size_t* str_len,
+       uint16_t option_code, uint8_t* option_data, size_t option_len);
+
+/**
+ * Scan wireformat EDNS OPT to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param pkt: packet with header and other info (may be NULL)
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_scan(uint8_t** data, size_t* data_len, char** str,
+       size_t* str_len, uint8_t* pkt, size_t pktlen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_WIRE2STR_H */
old mode 100755 (executable)
new mode 100644 (file)
similarity index 99%
rename from smallapp/unbound-control-setup.sh
rename to smallapp/unbound-control-setup.sh.in
index 29e4c1c..682ab26
@@ -36,7 +36,7 @@
 # settings:
 
 # directory for files
-DESTDIR=/usr/local/etc/unbound
+DESTDIR=@ub_conf_dir@
 
 # issuer and subject name for certificates
 SERVERNAME=unbound
diff --git a/testcode/run_vm.sh b/testcode/run_vm.sh
new file mode 100644 (file)
index 0000000..78649f0
--- /dev/null
@@ -0,0 +1,78 @@
+#!/usr/local/bin/bash
+# run tpkg tests from within a VM.  Looks for loopback addr.
+# if run not from within a VM, runs the tests as usual.
+# with one argument: run that tpkg, otherwise, run all tpkgs.
+
+get_lo0_ip4() {
+        if test -x /sbin/ifconfig
+        then
+                LO0_IP4=`/sbin/ifconfig lo0 | grep '[^0-9]127\.' | sed -e 's/^[^1]*\(127\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)[^0-9]*.*$/\1/g'`
+                if ( echo $LO0_IP4 | grep '^127\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' > /dev/null )
+                then
+                        return
+                fi
+        fi
+        LO0_IP4=127.0.0.1
+}
+get_lo0_ip4
+export LO0_IP4
+if test "x$LO0_IP4" = "x127.0.0.1"
+then
+        ALT_LOOPBACK=false
+else
+        ALT_LOOPBACK=true
+fi
+cd testdata
+TPKG=../testcode/mini_tpkg.sh
+#RUNLIST=`(ls -1 *.tpkg|grep -v '^0[016]')`
+RUNLIST=`(ls -1 *.tpkg)`
+if test "$#" = "1"; then RUNLIST="$1"; fi
+
+# fix up tpkg that was edited on keyboard interrupt.
+cleanup() {
+       echo cleanup
+       if test -f "$t.bak"; then mv "$t.bak" "$t"; fi
+       exit 0
+}
+trap cleanup SIGINT
+
+for t in $RUNLIST
+do
+       if ! $ALT_LOOPBACK
+       then
+               $TPKG exe $t
+               continue
+       fi
+       # We have alternative 127.0.0.1 number
+       if ( echo $t | grep '6\.tpkg$' ) # skip IPv6 tests
+       then
+               continue
+               elif test "$t" = "edns_cache.tpkg" # This one is IPv6 too!
+       then
+               continue
+       fi
+       cp -p "$t" "$t.bak"
+       tar xzf $t
+       find "${t%.tpkg}.dir" -type f \
+               -exec grep -q -e '127\.0\.0\.1' -e '@localhost' {} \; -print | {
+               while read f
+               do
+                       sed "s/127\.0\.0\.1/${LO0_IP4}/g" "$f" > "$f._"
+                       mv "$f._" "$f"
+                       sed "s/@localhost/@${LO0_IP4}/g" "$f" > "$f._"
+                       mv "$f._" "$f"
+               done
+       }
+       find "${t%.tpkg}.dir" -type d -name "127.0.0.1" -print | {
+               while read d
+               do
+                       mv -v "$d" "${d%127.0.0.1}${LO0_IP4}"
+               done
+       }
+       tar czf $t "${t%.tpkg}.dir"
+       rm -fr "${t%.tpkg}.dir"
+       $TPKG exe $t
+       mv "$t.bak" "$t"
+done
+# get out of testdata/
+cd ..
diff --git a/testdata/ctrl_pipe.tpkg b/testdata/ctrl_pipe.tpkg
new file mode 100644 (file)
index 0000000..877fcf9
Binary files /dev/null and b/testdata/ctrl_pipe.tpkg differ
diff --git a/testdata/dlv_remove.rpl b/testdata/dlv_remove.rpl
new file mode 100644 (file)
index 0000000..1b8b642
--- /dev/null
@@ -0,0 +1,197 @@
+; config options
+; The island of trust is at example.com (the DLV repository)
+server:
+       dlv-anchor: "example.com.    3600    IN      DS      2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
+       val-override-date: "20070916134226"
+       target-fetch-policy: "0 0 0 0 0"
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test validator with DLV anchor but DLV domain is down
+; so DLV has been decommissioned.
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN A
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+net. IN A
+SECTION AUTHORITY
+net.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com.    IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.     IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+net. IN NS
+SECTION ANSWER
+net.    IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.     IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.net. IN A
+SECTION AUTHORITY
+example.net.   IN NS   ns.example.net.
+SECTION ADDITIONAL
+ns.example.net.                IN      A       1.2.3.5
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+
+ENTRY_BEGIN
+MATCH opcode
+ADJUST copy_id copy_query
+REPLY QR SERVFAIL
+SECTION QUESTION
+example.com. IN NS
+ENTRY_END
+RANGE_END
+
+; ns.example.net.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.5
+; DS RR is
+; example.net. 3600    IN      DS      30899 5 1 14188c885f20623ad1d3bec42798f3f951793e4c ; xehac-mofum-malyd-bomaf-pegit-fuzes-ganin-misiz-nigel-nozog-soxix
+; DNSKEY prime query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.net. IN DNSKEY
+SECTION ANSWER
+example.net.    3600    IN      DNSKEY  256 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30899 (zsk), size = 512b}
+example.net.    3600    IN      RRSIG   DNSKEY RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. hiFzlQ8VoYgCuvIsfVuxC3mfJDqsTh0yc6abs5xMx5uEcIjb0dndFQx7INOM+imlzveEN73Hqp4OLFpFhsWLlw== ;{id = 30899}
+SECTION AUTHORITY
+example.net.    IN NS   ns.example.net.
+example.net.    3600    IN      RRSIG   NS RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. E8JX0l4B+cSR5bkHQwOJy1pBmlLMTYCJ8EwfNMU/eCv0YhKwo26rHhn52FGisgv+Nwp7/NbhHqQ+kJgoZC94XA== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.net.         IN      A       1.2.3.5
+ns.example.net. 3600    IN      RRSIG   A RSASHA1 3 3600 20070926134150 20070829134150 30899 example.net. x+tQMC9FhzT7Fcy1pM5NrOC7E8nLd7THPI3C6ie4EwL8PrxllqlR3q/DKB0d/m0qCOPcgN6HFOYURV1s4uAcsw== ;{id = 30899}
+ENTRY_END
+
+; NS query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.net. IN NS
+SECTION ANSWER
+example.net.    IN NS   ns.example.net.
+example.net.    3600    IN      RRSIG   NS RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. E8JX0l4B+cSR5bkHQwOJy1pBmlLMTYCJ8EwfNMU/eCv0YhKwo26rHhn52FGisgv+Nwp7/NbhHqQ+kJgoZC94XA== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.net.         IN      A       1.2.3.5
+ns.example.net. 3600    IN      RRSIG   A RSASHA1 3 3600 20070926134150 20070829134150 30899 example.net. x+tQMC9FhzT7Fcy1pM5NrOC7E8nLd7THPI3C6ie4EwL8PrxllqlR3q/DKB0d/m0qCOPcgN6HFOYURV1s4uAcsw== ;{id = 30899}
+ENTRY_END
+
+; www.example.net query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.net. IN A
+SECTION ANSWER
+www.example.net.       3600    IN      A       10.20.30.40
+www.example.net.       3600    IN      RRSIG   A 5 3 3600 20070926135752 20070829135752 30899 example.net. ACvv4RQVC7TbI57ewqFImRaVoymktJ5Cxn/FaCodIENt82LVM92nivbP2WtwWCsQHWp7FkrMxTlQTJwyAeXFyg== ;{id = 30899}
+SECTION AUTHORITY
+example.net.    IN NS   ns.example.net.
+example.net.    3600    IN      RRSIG   NS RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. E8JX0l4B+cSR5bkHQwOJy1pBmlLMTYCJ8EwfNMU/eCv0YhKwo26rHhn52FGisgv+Nwp7/NbhHqQ+kJgoZC94XA== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.net.         IN      A       1.2.3.5
+ns.example.net. 3600    IN      RRSIG   A RSASHA1 3 3600 20070926134150 20070829134150 30899 example.net. x+tQMC9FhzT7Fcy1pM5NrOC7E8nLd7THPI3C6ie4EwL8PrxllqlR3q/DKB0d/m0qCOPcgN6HFOYURV1s4uAcsw== ;{id = 30899}
+ENTRY_END
+
+
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.example.net. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA DO SERVFAIL
+SECTION QUESTION
+www.example.net. IN A
+SECTION ANSWER
+ENTRY_END
+
+SCENARIO_END
diff --git a/testdata/dlv_remove_empty.rpl b/testdata/dlv_remove_empty.rpl
new file mode 100644 (file)
index 0000000..30afced
--- /dev/null
@@ -0,0 +1,270 @@
+; config options
+; The island of trust is at example.com (the DLV repository)
+server:
+       dlv-anchor: "example.com.    3600    IN      DS      2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
+       val-override-date: "20070916134226"
+       target-fetch-policy: "0 0 0 0 0"
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test validator with DLV and DLV repository is empty.
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN A
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+net. IN A
+SECTION AUTHORITY
+net.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com.    IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.     IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+net. IN NS
+SECTION ANSWER
+net.    IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.     IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.net. IN A
+SECTION AUTHORITY
+example.net.   IN NS   ns.example.net.
+SECTION ADDITIONAL
+ns.example.net.                IN      A       1.2.3.5
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; response to DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN DNSKEY
+SECTION ANSWER
+example.com.    3600    IN      DNSKEY  256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
+example.com.    3600    IN      RRSIG   DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; DLV query, everything is NXDOMAIN
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR AA NXDOMAIN
+SECTION QUESTION
+example.com. IN DLV
+SECTION ANSWER
+SECTION AUTHORITY
+example.com.   3600    IN      NSEC    example.com. NS SOA RRSIG NSEC DNSKEY 
+example.com.   3600    IN      RRSIG   NSEC 3 2 3600 20070926135752 20070829135752 2854 example.com. AH++lP1qhsBw6zO1g3JVPZeQIpDhL9xT8V9xdgjXvCjIGQ1BUUlfQkA=
+SECTION ADDITIONAL
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+net.example.com. IN DLV
+SECTION ANSWER
+SECTION AUTHORITY
+example.com. IN SOA open.nlnetlabs.nl. hostmaster.nlnetlabs.nl. 2008081300 28800 7200 604800 3600
+example.com.   3600    IN      RRSIG   SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. AKPJnPBqfJKxE4P2iVYkSRJno9HmiXJZtjdqE8oBeq9Lk9FytcMdcig= ;{id = 2854}
+example.com IN NSEC example.net.example.com. SOA NS RRSIG NSEC
+example.com.   3600    IN      RRSIG   NSEC 3 2 3600 20070926134150 20070829134150 2854 example.com. AIoUkJ04/7/kJFDLocoqksqt9UL2RHHwlRfXAMxGdBHcNO+GSpG47Uk= ;{id = 2854}
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NXDOMAIN
+SECTION QUESTION
+com.example.com. IN DLV
+SECTION ANSWER
+SECTION AUTHORITY
+example.com. IN SOA open.nlnetlabs.nl. hostmaster.nlnetlabs.nl. 2008081300 28800 7200 604800 3600
+example.com.   3600    IN      RRSIG   SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. AKPJnPBqfJKxE4P2iVYkSRJno9HmiXJZtjdqE8oBeq9Lk9FytcMdcig= ;{id = 2854}
+example.com IN NSEC example.net.example.com. SOA NS RRSIG NSEC
+example.com.   3600    IN      RRSIG   NSEC 3 2 3600 20070926134150 20070829134150 2854 example.com. AIoUkJ04/7/kJFDLocoqksqt9UL2RHHwlRfXAMxGdBHcNO+GSpG47Uk= ;{id = 2854}
+ENTRY_END
+
+RANGE_END
+
+; ns.example.net.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.5
+; DS RR is
+; example.net. 3600    IN      DS      30899 5 1 14188c885f20623ad1d3bec42798f3f951793e4c ; xehac-mofum-malyd-bomaf-pegit-fuzes-ganin-misiz-nigel-nozog-soxix
+; DNSKEY prime query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.net. IN DNSKEY
+SECTION ANSWER
+example.net.    3600    IN      DNSKEY  256 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30899 (zsk), size = 512b}
+example.net.    3600    IN      RRSIG   DNSKEY RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. hiFzlQ8VoYgCuvIsfVuxC3mfJDqsTh0yc6abs5xMx5uEcIjb0dndFQx7INOM+imlzveEN73Hqp4OLFpFhsWLlw== ;{id = 30899}
+SECTION AUTHORITY
+example.net.    IN NS   ns.example.net.
+example.net.    3600    IN      RRSIG   NS RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. E8JX0l4B+cSR5bkHQwOJy1pBmlLMTYCJ8EwfNMU/eCv0YhKwo26rHhn52FGisgv+Nwp7/NbhHqQ+kJgoZC94XA== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.net.         IN      A       1.2.3.5
+ns.example.net. 3600    IN      RRSIG   A RSASHA1 3 3600 20070926134150 20070829134150 30899 example.net. x+tQMC9FhzT7Fcy1pM5NrOC7E8nLd7THPI3C6ie4EwL8PrxllqlR3q/DKB0d/m0qCOPcgN6HFOYURV1s4uAcsw== ;{id = 30899}
+ENTRY_END
+
+; NS query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.net. IN NS
+SECTION ANSWER
+example.net.    IN NS   ns.example.net.
+example.net.    3600    IN      RRSIG   NS RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. E8JX0l4B+cSR5bkHQwOJy1pBmlLMTYCJ8EwfNMU/eCv0YhKwo26rHhn52FGisgv+Nwp7/NbhHqQ+kJgoZC94XA== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.net.         IN      A       1.2.3.5
+ns.example.net. 3600    IN      RRSIG   A RSASHA1 3 3600 20070926134150 20070829134150 30899 example.net. x+tQMC9FhzT7Fcy1pM5NrOC7E8nLd7THPI3C6ie4EwL8PrxllqlR3q/DKB0d/m0qCOPcgN6HFOYURV1s4uAcsw== ;{id = 30899}
+ENTRY_END
+
+; www.example.net query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.net. IN A
+SECTION ANSWER
+www.example.net.       3600    IN      A       10.20.30.40
+www.example.net.       3600    IN      RRSIG   A 5 3 3600 20070926135752 20070829135752 30899 example.net. ACvv4RQVC7TbI57ewqFImRaVoymktJ5Cxn/FaCodIENt82LVM92nivbP2WtwWCsQHWp7FkrMxTlQTJwyAeXFyg== ;{id = 30899}
+SECTION AUTHORITY
+example.net.    IN NS   ns.example.net.
+example.net.    3600    IN      RRSIG   NS RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. E8JX0l4B+cSR5bkHQwOJy1pBmlLMTYCJ8EwfNMU/eCv0YhKwo26rHhn52FGisgv+Nwp7/NbhHqQ+kJgoZC94XA== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.net.         IN      A       1.2.3.5
+ns.example.net. 3600    IN      RRSIG   A RSASHA1 3 3600 20070926134150 20070829134150 30899 example.net. x+tQMC9FhzT7Fcy1pM5NrOC7E8nLd7THPI3C6ie4EwL8PrxllqlR3q/DKB0d/m0qCOPcgN6HFOYURV1s4uAcsw== ;{id = 30899}
+ENTRY_END
+
+
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.example.net. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA DO NOERROR
+SECTION QUESTION
+www.example.net. IN A
+SECTION ANSWER
+www.example.net.       3600    IN      A       10.20.30.40
+www.example.net.       3600    IN      RRSIG   A 5 3 3600 20070926135752 20070829135752 30899 example.net. ACvv4RQVC7TbI57ewqFImRaVoymktJ5Cxn/FaCodIENt82LVM92nivbP2WtwWCsQHWp7FkrMxTlQTJwyAeXFyg== ;{id = 30899}
+SECTION AUTHORITY
+example.net.    IN NS   ns.example.net.
+example.net.    3600    IN      RRSIG   NS RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. E8JX0l4B+cSR5bkHQwOJy1pBmlLMTYCJ8EwfNMU/eCv0YhKwo26rHhn52FGisgv+Nwp7/NbhHqQ+kJgoZC94XA== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.net.         IN      A       1.2.3.5
+ns.example.net. 3600    IN      RRSIG   A RSASHA1 3 3600 20070926134150 20070829134150 30899 example.net. x+tQMC9FhzT7Fcy1pM5NrOC7E8nLd7THPI3C6ie4EwL8PrxllqlR3q/DKB0d/m0qCOPcgN6HFOYURV1s4uAcsw== ;{id = 30899}
+ENTRY_END
+
+SCENARIO_END
diff --git a/testdata/dlv_remove_nodel.rpl b/testdata/dlv_remove_nodel.rpl
new file mode 100644 (file)
index 0000000..799e841
--- /dev/null
@@ -0,0 +1,274 @@
+; config options
+; The island of trust is at example.com (the DLV repository)
+server:
+       dlv-anchor: "dlv.example.com.    3600    IN      DS      2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
+       trust-anchor: "example.com.    3600    IN      DS      2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
+       val-override-date: "20070916134226"
+       target-fetch-policy: "0 0 0 0 0"
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test validator with DLV and DLV is removed and not delegated
+; so the response is that the dlv domain itself does not exist, but it's
+; parent domain does exist (securely).
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN A
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+net. IN A
+SECTION AUTHORITY
+net.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com.    IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.     IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+net. IN NS
+SECTION ANSWER
+net.    IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.     IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.net. IN A
+SECTION AUTHORITY
+example.net.   IN NS   ns.example.net.
+SECTION ADDITIONAL
+ns.example.net.                IN      A       1.2.3.5
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; response to DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN DNSKEY
+SECTION ANSWER
+example.com.    3600    IN      DNSKEY  256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
+example.com.    3600    IN      RRSIG   DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; DLV query, everything is NXDOMAIN
+; thus, no delegation to the dlv repository in dlv.example.com
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR AA NXDOMAIN
+SECTION QUESTION
+example.com. IN DLV
+SECTION ANSWER
+SECTION AUTHORITY
+example.com.   3600    IN      NSEC    example.com. NS SOA RRSIG NSEC DNSKEY 
+example.com.   3600    IN      RRSIG   NSEC 3 2 3600 20070926135752 20070829135752 2854 example.com. AH++lP1qhsBw6zO1g3JVPZeQIpDhL9xT8V9xdgjXvCjIGQ1BUUlfQkA=
+SECTION ADDITIONAL
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+net.example.com. IN DLV
+SECTION ANSWER
+SECTION AUTHORITY
+example.com. IN SOA open.nlnetlabs.nl. hostmaster.nlnetlabs.nl. 2008081300 28800 7200 604800 3600
+example.com.   3600    IN      RRSIG   SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. AKPJnPBqfJKxE4P2iVYkSRJno9HmiXJZtjdqE8oBeq9Lk9FytcMdcig= ;{id = 2854}
+example.com IN NSEC example.net.example.com. SOA NS RRSIG NSEC
+example.com.   3600    IN      RRSIG   NSEC 3 2 3600 20070926134150 20070829134150 2854 example.com. AIoUkJ04/7/kJFDLocoqksqt9UL2RHHwlRfXAMxGdBHcNO+GSpG47Uk= ;{id = 2854}
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NXDOMAIN
+SECTION QUESTION
+com.example.com. IN DLV
+SECTION ANSWER
+SECTION AUTHORITY
+example.com. IN SOA open.nlnetlabs.nl. hostmaster.nlnetlabs.nl. 2008081300 28800 7200 604800 3600
+example.com.   3600    IN      RRSIG   SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. AKPJnPBqfJKxE4P2iVYkSRJno9HmiXJZtjdqE8oBeq9Lk9FytcMdcig= ;{id = 2854}
+example.com IN NSEC example.net.example.com. SOA NS RRSIG NSEC
+example.com.   3600    IN      RRSIG   NSEC 3 2 3600 20070926134150 20070829134150 2854 example.com. AIoUkJ04/7/kJFDLocoqksqt9UL2RHHwlRfXAMxGdBHcNO+GSpG47Uk= ;{id = 2854}
+ENTRY_END
+
+RANGE_END
+
+; ns.example.net.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.5
+; DS RR is
+; example.net. 3600    IN      DS      30899 5 1 14188c885f20623ad1d3bec42798f3f951793e4c ; xehac-mofum-malyd-bomaf-pegit-fuzes-ganin-misiz-nigel-nozog-soxix
+; DNSKEY prime query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.net. IN DNSKEY
+SECTION ANSWER
+example.net.    3600    IN      DNSKEY  256 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30899 (zsk), size = 512b}
+example.net.    3600    IN      RRSIG   DNSKEY RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. hiFzlQ8VoYgCuvIsfVuxC3mfJDqsTh0yc6abs5xMx5uEcIjb0dndFQx7INOM+imlzveEN73Hqp4OLFpFhsWLlw== ;{id = 30899}
+SECTION AUTHORITY
+example.net.    IN NS   ns.example.net.
+example.net.    3600    IN      RRSIG   NS RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. E8JX0l4B+cSR5bkHQwOJy1pBmlLMTYCJ8EwfNMU/eCv0YhKwo26rHhn52FGisgv+Nwp7/NbhHqQ+kJgoZC94XA== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.net.         IN      A       1.2.3.5
+ns.example.net. 3600    IN      RRSIG   A RSASHA1 3 3600 20070926134150 20070829134150 30899 example.net. x+tQMC9FhzT7Fcy1pM5NrOC7E8nLd7THPI3C6ie4EwL8PrxllqlR3q/DKB0d/m0qCOPcgN6HFOYURV1s4uAcsw== ;{id = 30899}
+ENTRY_END
+
+; NS query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.net. IN NS
+SECTION ANSWER
+example.net.    IN NS   ns.example.net.
+example.net.    3600    IN      RRSIG   NS RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. E8JX0l4B+cSR5bkHQwOJy1pBmlLMTYCJ8EwfNMU/eCv0YhKwo26rHhn52FGisgv+Nwp7/NbhHqQ+kJgoZC94XA== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.net.         IN      A       1.2.3.5
+ns.example.net. 3600    IN      RRSIG   A RSASHA1 3 3600 20070926134150 20070829134150 30899 example.net. x+tQMC9FhzT7Fcy1pM5NrOC7E8nLd7THPI3C6ie4EwL8PrxllqlR3q/DKB0d/m0qCOPcgN6HFOYURV1s4uAcsw== ;{id = 30899}
+ENTRY_END
+
+; www.example.net query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.net. IN A
+SECTION ANSWER
+www.example.net.       3600    IN      A       10.20.30.40
+www.example.net.       3600    IN      RRSIG   A 5 3 3600 20070926135752 20070829135752 30899 example.net. ACvv4RQVC7TbI57ewqFImRaVoymktJ5Cxn/FaCodIENt82LVM92nivbP2WtwWCsQHWp7FkrMxTlQTJwyAeXFyg== ;{id = 30899}
+SECTION AUTHORITY
+example.net.    IN NS   ns.example.net.
+example.net.    3600    IN      RRSIG   NS RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. E8JX0l4B+cSR5bkHQwOJy1pBmlLMTYCJ8EwfNMU/eCv0YhKwo26rHhn52FGisgv+Nwp7/NbhHqQ+kJgoZC94XA== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.net.         IN      A       1.2.3.5
+ns.example.net. 3600    IN      RRSIG   A RSASHA1 3 3600 20070926134150 20070829134150 30899 example.net. x+tQMC9FhzT7Fcy1pM5NrOC7E8nLd7THPI3C6ie4EwL8PrxllqlR3q/DKB0d/m0qCOPcgN6HFOYURV1s4uAcsw== ;{id = 30899}
+ENTRY_END
+
+
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.example.net. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA DO NOERROR
+SECTION QUESTION
+www.example.net. IN A
+SECTION ANSWER
+www.example.net.       3600    IN      A       10.20.30.40
+www.example.net.       3600    IN      RRSIG   A 5 3 3600 20070926135752 20070829135752 30899 example.net. ACvv4RQVC7TbI57ewqFImRaVoymktJ5Cxn/FaCodIENt82LVM92nivbP2WtwWCsQHWp7FkrMxTlQTJwyAeXFyg== ;{id = 30899}
+SECTION AUTHORITY
+example.net.    IN NS   ns.example.net.
+example.net.    3600    IN      RRSIG   NS RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. E8JX0l4B+cSR5bkHQwOJy1pBmlLMTYCJ8EwfNMU/eCv0YhKwo26rHhn52FGisgv+Nwp7/NbhHqQ+kJgoZC94XA== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.net.         IN      A       1.2.3.5
+ns.example.net. 3600    IN      RRSIG   A RSASHA1 3 3600 20070926134150 20070829134150 30899 example.net. x+tQMC9FhzT7Fcy1pM5NrOC7E8nLd7THPI3C6ie4EwL8PrxllqlR3q/DKB0d/m0qCOPcgN6HFOYURV1s4uAcsw== ;{id = 30899}
+ENTRY_END
+
+SCENARIO_END
diff --git a/testdata/dlv_remove_pos.rpl b/testdata/dlv_remove_pos.rpl
new file mode 100644 (file)
index 0000000..de7da44
--- /dev/null
@@ -0,0 +1,163 @@
+; config options
+; The island of trust is at example.com
+server:
+       dlv-anchor: "dlv.example.net.    3600    IN      DS      2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
+       trust-anchor: "example.com.    3600    IN      DS      2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
+       val-override-date: "20070916134226"
+       target-fetch-policy: "0 0 0 0 0"
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test validator with DLV removed for positive anchored response
+; So the destination has a valid DNSSEC chain of trust to the root,
+; but the configured dlv anchor fails.
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+
+; this covers dlv.example.net and thus makes it servfail (unusable).
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR SERVFAIL
+SECTION QUESTION
+net. IN NS
+ENTRY_END
+
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com.    IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.     IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; response to DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN DNSKEY
+SECTION ANSWER
+example.com.    3600    IN      DNSKEY  256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
+example.com.    3600    IN      RRSIG   DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; response to query of interest
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+www.example.com.        3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA AD DO NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+www.example.com.        3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
+ENTRY_END
+
+SCENARIO_END
diff --git a/testdata/dns64_lookup.rpl b/testdata/dns64_lookup.rpl
new file mode 100644 (file)
index 0000000..5d4a63b
--- /dev/null
@@ -0,0 +1,211 @@
+; config options
+server:
+       target-fetch-policy: "0 0 0 0 0"
+       module-config: "dns64 validator iterator"
+       dns64-prefix: 64:ff9b::0/96
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test dns64 lookup and synthesis.
+; normal A lookup should still succeed
+; AAAA is synthesized if not present.
+; AAAA if present, is passed through unchanged.
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ip4.example.com. IN AAAA
+SECTION ANSWER
+; NO AAAA present
+SECTION AUTHORITY
+example.com.   IN SOA  a. b. 1 2 3 4 5
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ip4.example.com. IN A
+SECTION ANSWER
+ip4.example.com. IN A  5.6.7.8
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ip6.example.com. IN AAAA
+SECTION ANSWER
+ip6.example.com. IN AAAA 1:2:3::4
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+; synthesize from A record 5.6.7.8
+STEP 20 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+ip4.example.com. IN AAAA
+ENTRY_END
+
+; recursion happens here.
+STEP 30 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+ip4.example.com. IN AAAA
+SECTION ANSWER
+ip4.example.com.        IN      AAAA    64:ff9b::506:708
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+; this node has its own ipv6 address
+STEP 40 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+ip6.example.com. IN AAAA
+ENTRY_END
+
+; recursion happens here.
+STEP 50 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+ip6.example.com. IN AAAA
+SECTION ANSWER
+ip6.example.com. IN AAAA 1:2:3::4
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+SCENARIO_END
diff --git a/testdata/fwd_capsid_strip.tpkg b/testdata/fwd_capsid_strip.tpkg
new file mode 100644 (file)
index 0000000..c0be8a3
Binary files /dev/null and b/testdata/fwd_capsid_strip.tpkg differ
diff --git a/testdata/val_spurious_ns.rpl b/testdata/val_spurious_ns.rpl
new file mode 100644 (file)
index 0000000..741fd1a
--- /dev/null
@@ -0,0 +1,151 @@
+; config options
+; The island of trust is at example.com
+server:
+       trust-anchor: "example.com.    3600    IN      DS      2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
+       val-override-date: "20070916134226"
+       target-fetch-policy: "0 0 0 0 0"
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test validator with spurious unsigned NS in auth section 
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com.    IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.     IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; response to DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN DNSKEY
+SECTION ANSWER
+example.com.    3600    IN      DNSKEY  256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
+example.com.    3600    IN      RRSIG   DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; response to query of interest
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+;example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+www.example.com.        3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA AD DO NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+www.example.com.        3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
+SECTION AUTHORITY
+; removed by spurious NS record removal code
+;;example.com. IN NS   ns.example.com.
+;;example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
+ENTRY_END
+
+SCENARIO_END
diff --git a/testdata/val_ta_algo_dnskey_dp.rpl b/testdata/val_ta_algo_dnskey_dp.rpl
new file mode 100644 (file)
index 0000000..b23c0f1
--- /dev/null
@@ -0,0 +1,182 @@
+; config options
+; The island of trust is at example.com
+server:
+       trust-anchor: "example.com.     3600    IN      DNSKEY  256 3 3 ALXLUsWqUrY3JYER3T4TBJIIs70j+sDS/UT2QRp61SE7S3EEXopNXoFE73JLRmvpi/UrOO/Vz4Se6wXv/CYCKjGw06U4WRgRYXcpEhJROyNapmdIKSxhOzfLVE1gqA0PweZR8dtY3aNQSRn3sPpwJr6Mi/PqQKAMMrZ9ckJpf1+bQMOOvxgzz2U1GS18b3yZKcgTMEaJzd/GZYzi/BN2DzQ0MsrSwYXfsNLFOBbs8PJMW4LYIxeeOe6rUgkWOF7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}"
+       trust-anchor: "example.com.     3600    IN      DS      30899 5 1 d4bf9d2e10f6d76840d42ef5913022abcd0bf512"
+       val-override-date: "20070916134226"
+       target-fetch-policy: "0 0 0 0 0"
+       harden-algo-downgrade: no
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test validator with multiple algorithm trust anchor without harden 
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com.    IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.     IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+example.com.   3600    IN      RRSIG   NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ns.example.com.        3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899}
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+example.com.   3600    IN      RRSIG   NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ns.example.com.        3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899}
+ENTRY_END
+
+
+; response to DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN DNSKEY
+SECTION ANSWER
+example.com.   3600    IN      DNSKEY  256 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30899 (zsk), size = 512b}
+example.com.   3600    IN      DNSKEY  256 3 3 ALXLUsWqUrY3JYER3T4TBJIIs70j+sDS/UT2QRp61SE7S3EEXopNXoFE73JLRmvpi/UrOO/Vz4Se6wXv/CYCKjGw06U4WRgRYXcpEhJROyNapmdIKSxhOzfLVE1gqA0PweZR8dtY3aNQSRn3sPpwJr6Mi/PqQKAMMrZ9ckJpf1+bQMOOvxgzz2U1GS18b3yZKcgTMEaJzd/GZYzi/BN2DzQ0MsrSwYXfsNLFOBbs8PJMW4LYIxeeOe6rUgkWOF7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 512b}
+example.com.   3600    IN      RRSIG   DNSKEY 3 2 3600 20070926134150 20070829134150 2854 example.com. AKIIYDOGHogglFqJK94ZtOnF7EfGikgAyloMNRSMCrQgFaFkmcOyjrc= ;{id = 2854}
+example.com.   3600    IN      RRSIG   DNSKEY 5 2 3600 20070926134150 20070829134150 30899 example.com. J55fsz1GGMnngc4r50xvXDUdaVMlfcLKLVsfMhwNLF+ERac5XV/lLRAc/aSER+qQdsSo0CrjYjy1wat7YQpDAA== ;{id = 30899}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+example.com.   3600    IN      RRSIG   NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ns.example.com.        3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899}
+ENTRY_END
+
+; response to query of interest
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
+www.example.com.       3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. JNWECShNE+nCLQwOXJJ3xpUkh2G+FCh5nk8uYAHIVQRse/BIvCMSlvRrtVyw9RnXvk5RR2bEgN0pRdLWW7ug5Q== ;{id = 30899}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+example.com.   3600    IN      RRSIG   NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+www.example.com.        3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
+ns.example.com.        3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899}
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA AD DO NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+www.example.com.       3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. JNWECShNE+nCLQwOXJJ3xpUkh2G+FCh5nk8uYAHIVQRse/BIvCMSlvRrtVyw9RnXvk5RR2bEgN0pRdLWW7ug5Q== ;{id = 30899}
+www.example.com.        3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+example.com.   3600    IN      RRSIG   NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
+ns.example.com.        3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899}
+ENTRY_END
+
+SCENARIO_END
diff --git a/testdata/val_ta_algo_missing_dp.rpl b/testdata/val_ta_algo_missing_dp.rpl
new file mode 100644 (file)
index 0000000..2cf0556
--- /dev/null
@@ -0,0 +1,185 @@
+; config options
+; The island of trust is at example.com
+server:
+       trust-anchor: "example.com.     3600    IN      DNSKEY  256 3 3 ALXLUsWqUrY3JYER3T4TBJIIs70j+sDS/UT2QRp61SE7S3EEXopNXoFE73JLRmvpi/UrOO/Vz4Se6wXv/CYCKjGw06U4WRgRYXcpEhJROyNapmdIKSxhOzfLVE1gqA0PweZR8dtY3aNQSRn3sPpwJr6Mi/PqQKAMMrZ9ckJpf1+bQMOOvxgzz2U1GS18b3yZKcgTMEaJzd/GZYzi/BN2DzQ0MsrSwYXfsNLFOBbs8PJMW4LYIxeeOe6rUgkWOF7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}"
+       trust-anchor: "example.com.     3600    IN      DS      30899 5 1 d4bf9d2e10f6d76840d42ef5913022abcd0bf512"
+       trust-anchor: "example.com.     3600    IN      DS      30899 7 1 d4bf9d2e10f6d76840d42ef5913022abcd0bf512"
+       val-override-date: "20070916134226"
+       target-fetch-policy: "0 0 0 0 0"
+       harden-algo-downgrade: no
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test validator with multiple algorithm missing one
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com.    IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.     IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+example.com.   3600    IN      RRSIG   NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ns.example.com.        3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899}
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+example.com.   3600    IN      RRSIG   NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ns.example.com.        3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899}
+ENTRY_END
+
+
+; response to DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN DNSKEY
+SECTION ANSWER
+example.com.   3600    IN      DNSKEY  256 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30899 (zsk), size = 512b}
+example.com.   3600    IN      DNSKEY  256 3 3 ALXLUsWqUrY3JYER3T4TBJIIs70j+sDS/UT2QRp61SE7S3EEXopNXoFE73JLRmvpi/UrOO/Vz4Se6wXv/CYCKjGw06U4WRgRYXcpEhJROyNapmdIKSxhOzfLVE1gqA0PweZR8dtY3aNQSRn3sPpwJr6Mi/PqQKAMMrZ9ckJpf1+bQMOOvxgzz2U1GS18b3yZKcgTMEaJzd/GZYzi/BN2DzQ0MsrSwYXfsNLFOBbs8PJMW4LYIxeeOe6rUgkWOF7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 512b}
+example.com.   3600    IN      RRSIG   DNSKEY 3 2 3600 20070926134150 20070829134150 2854 example.com. AKIIYDOGHogglFqJK94ZtOnF7EfGikgAyloMNRSMCrQgFaFkmcOyjrc= ;{id = 2854}
+example.com.   3600    IN      RRSIG   DNSKEY 5 2 3600 20070926134150 20070829134150 30899 example.com. J55fsz1GGMnngc4r50xvXDUdaVMlfcLKLVsfMhwNLF+ERac5XV/lLRAc/aSER+qQdsSo0CrjYjy1wat7YQpDAA== ;{id = 30899}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+example.com.   3600    IN      RRSIG   NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ns.example.com.        3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899}
+ENTRY_END
+
+; response to query of interest
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
+www.example.com.       3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. JNWECShNE+nCLQwOXJJ3xpUkh2G+FCh5nk8uYAHIVQRse/BIvCMSlvRrtVyw9RnXvk5RR2bEgN0pRdLWW7ug5Q== ;{id = 30899}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+example.com.   3600    IN      RRSIG   NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+www.example.com.        3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
+ns.example.com.        3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899}
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA AD DO NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com.       3600    IN      A       10.20.30.40
+www.example.com.       3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. JNWECShNE+nCLQwOXJJ3xpUkh2G+FCh5nk8uYAHIVQRse/BIvCMSlvRrtVyw9RnXvk5RR2bEgN0pRdLWW7ug5Q== ;{id = 30899}
+www.example.com.       3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
+
+SECTION AUTHORITY
+example.com.   3600    IN      NS      ns.example.com.
+example.com.   3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+example.com.   3600    IN      RRSIG   NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899}
+
+SECTION ADDITIONAL
+ns.example.com.        3600    IN      A       1.2.3.4
+ns.example.com.        3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
+ns.example.com.        3600    IN      RRSIG   A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899}
+ENTRY_END
+
+SCENARIO_END