Parcourir la source

Merged b10-loadzone command

git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@1139 e5f2f494-b856-4b98-b285-d166d9295462
Evan Hunt il y a 15 ans
Parent
commit
98062144f4

+ 6 - 0
configure.ac

@@ -149,12 +149,14 @@ AC_CONFIG_FILES([Makefile
                  src/bin/bindctl/Makefile
                  src/bin/bindctl/Makefile
                  src/bin/cfgmgr/Makefile
                  src/bin/cfgmgr/Makefile
                  src/bin/host/Makefile
                  src/bin/host/Makefile
+                 src/bin/loadzone/Makefile
                  src/bin/msgq/Makefile
                  src/bin/msgq/Makefile
                  src/bin/auth/Makefile
                  src/bin/auth/Makefile
                  src/lib/Makefile
                  src/lib/Makefile
                  src/lib/cc/Makefile
                  src/lib/cc/Makefile
                  src/lib/python/Makefile
                  src/lib/python/Makefile
                  src/lib/python/isc/Makefile
                  src/lib/python/isc/Makefile
+                 src/lib/python/isc/auth/Makefile
                  src/lib/python/isc/cc/Makefile
                  src/lib/python/isc/cc/Makefile
                  src/lib/python/isc/config/Makefile
                  src/lib/python/isc/config/Makefile
                  src/lib/python/isc/Util/Makefile
                  src/lib/python/isc/Util/Makefile
@@ -173,6 +175,8 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
            src/bin/bind10/run_bind10.sh
            src/bin/bind10/run_bind10.sh
            src/bin/bindctl/bindctl
            src/bin/bindctl/bindctl
            src/bin/bindctl/unittest/bindctl_test
            src/bin/bindctl/unittest/bindctl_test
+           src/bin/loadzone/run_loadzone
+           src/bin/loadzone/b10-loadzone.py
            src/bin/msgq/msgq.py
            src/bin/msgq/msgq.py
            src/bin/msgq/msgq_test
            src/bin/msgq/msgq_test
            src/bin/msgq/run_msgq.sh
            src/bin/msgq/run_msgq.sh
@@ -187,6 +191,8 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
            chmod +x src/bin/cmdctl/unittest/cmdctl_test
            chmod +x src/bin/cmdctl/unittest/cmdctl_test
            chmod +x src/bin/bindctl/unittest/bindctl_test
            chmod +x src/bin/bindctl/unittest/bindctl_test
            chmod +x src/bin/bindctl/bindctl
            chmod +x src/bin/bindctl/bindctl
+           chmod +x src/bin/loadzone/b10-loadzone
+           chmod +x src/bin/loadzone/run_loadzone
            chmod +x src/bin/msgq/run_msgq.sh
            chmod +x src/bin/msgq/run_msgq.sh
            chmod +x src/bin/msgq/msgq_test
            chmod +x src/bin/msgq/msgq_test
 	   chmod +x src/lib/dns/gen-rdatacode.py
 	   chmod +x src/lib/dns/gen-rdatacode.py

+ 1 - 1
src/bin/Makefile.am

@@ -1 +1 @@
-SUBDIRS = bind10 bindctl cfgmgr msgq host cmdctl auth
+SUBDIRS = bind10 bindctl cfgmgr loadzone msgq host cmdctl auth

+ 6 - 0
src/bin/loadzone/Makefile.am

@@ -0,0 +1,6 @@
+bin_SCRIPTS = b10-loadzone
+
+b10-loadzone: b10-loadzone.py
+	$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
+	       -e "s|@@LIBEXECDIR@@|$(pkglibexecdir)|" b10-loadzone.py >$@
+	chmod a+x $@

+ 1 - 0
src/bin/loadzone/__init__.py

@@ -0,0 +1 @@
+__all__ = ['mycollections', 'exception', 'moduleinfo', 'command', 'bindctl']

+ 70 - 0
src/bin/loadzone/b10-loadzone.py.in

@@ -0,0 +1,70 @@
+#!@PYTHON@
+# Copyright (C) 2010  Internet Systems Consortium.
+#
+# 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 INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM 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.
+
+import sys; sys.path.append ('@@PYTHONPATH@@')
+import re, getopt
+import isc
+
+#########################################################################
+# usage: print usage note and exit
+#########################################################################
+def usage():
+    print("Usage: %s [-d <database>] [-o <origin>] <file>" % sys.argv[0], \
+          file=sys.stderr)
+    exit(1)
+
+#########################################################################
+# main
+#########################################################################
+def main():
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "d:o:h", \
+                                                ["dbfile", "origin", "help"])
+    except getopt.GetoptError as e:
+        print(str(e))
+        usage()
+        exit(2)
+
+    dbfile = '/tmp/zone.sqlite3'
+    initial_origin = '.'
+    for o, a in opts:
+        if o in ("-d", "--dbfile"):
+            dbfile = a
+        elif o in ("-o", "--origin"):
+            initial_origin = a
+        elif o in ("-h", "--help"):
+            usage()
+        else:
+            assert False, "unhandled option"
+
+    if len(args) != 1:
+        usage()
+    zonefile = args[0]
+
+    try:
+        zone, zonedata = isc.auth.master.parse(zonefile, initial_origin)
+    except Exception as e:
+        print("Error reading zone file: " + str(e))
+        exit(1)
+
+    try:
+        isc.auth.sqlite3_ds.load(dbfile, zone, zonedata)
+    except Exception as e:
+        print("Error loading database: " + str(e))
+        exit(1)
+
+if __name__ == "__main__":
+    main()

+ 10 - 0
src/bin/loadzone/run_loadzone.in

@@ -0,0 +1,10 @@
+#! /bin/sh
+
+PYTHON_EXEC=${PYTHON_EXEC:-@PYTHON@}
+export PYTHON_EXEC
+
+PYTHONPATH=@abs_top_builddir@/src/lib/python
+export PYTHONPATH
+
+LOADZONE_PATH=@abs_top_srcdir@/src/bin/loadzone
+exec ${LOADZONE_PATH}/b10-loadzone $*

+ 5 - 0
src/bin/loadzone/testdata/Kexample.com.+005+04456.key

@@ -0,0 +1,5 @@
+; This is a key-signing key, keyid 4456, for example.com.
+; Created: Tue Feb 16 22:50:31 2010
+; Publish: Tue Feb 16 22:50:31 2010
+; Activate: Tue Feb 16 22:50:31 2010
+example.com. IN DNSKEY 257 3 5 AwEAAe5WFbxdCPq2jZrZhlMj7oJdff3W7syJtbvzg62tRx0gkoCDoBI9 DPjlOQG0UAbj+xUV4HQZJStJaZ+fHU5AwVNT+bBZdtV+NujSikhdTHb4 FYLg2b3Cx9NyJvAVukHp/91HnWuG4T36CzAFrfPwsHIrBz9BsaIQ21VR kcmj7DswfI/iDGd8j6bqiODyNZYQ+ZrLmF0KIJ2yPN3iO6Zq23TaOrVT jB7d1a/h31ODfiHAxFHrkY3t3D5JR9Nsl/7fdRmSznwtcSDgLXBoFEYm w6p86AcvRyoYNcL1SXjaKVLG5jyU3UR+LcGZT5t/0xGfoIK/aKwENrsj cKZZj660b1M=

+ 13 - 0
src/bin/loadzone/testdata/Kexample.com.+005+04456.private

@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 5 (RSASHA1)
+Modulus: 7lYVvF0I+raNmtmGUyPugl19/dbuzIm1u/ODra1HHSCSgIOgEj0M+OU5AbRQBuP7FRXgdBklK0lpn58dTkDBU1P5sFl21X426NKKSF1MdvgVguDZvcLH03Im8BW6Qen/3Ueda4bhPfoLMAWt8/CwcisHP0GxohDbVVGRyaPsOzB8j+IMZ3yPpuqI4PI1lhD5msuYXQognbI83eI7pmrbdNo6tVOMHt3Vr+HfU4N+IcDEUeuRje3cPklH02yX/t91GZLOfC1xIOAtcGgURibDqnzoBy9HKhg1wvVJeNopUsbmPJTdRH4twZlPm3/TEZ+ggr9orAQ2uyNwplmPrrRvUw==
+PublicExponent: AQAB
+PrivateExponent: MiGnVsSW8+1cIbspduly7LbvnmoMNreso0kYZHqzH5xPVHrbO5rd1KiachJUVu6zTH8ahDEZ0V4SuoGEb4ZNY9KhDYfz5/oxYI2QiqIdSFTsaWgURMbos0AqkotvbxfiOtAqe4iWbivfGI3JRitVYd5NGvAdhgJXsD2FFc3GDbjAPgPK8lVIOW/q6azovq/eCf/RPgExqVEaLegOYBZrxsn6VXxwiDH2i6IDlSfCjMax7nq563msDxwhEKAujnrxh9rn5jzNlIiAy4wDHybyhSCvity72PgB7CsPCECtW17iA4uVkJo93XZIb9dbZc7m986SM3JersSBYaDTnz7tMQ==
+Prime1: +pe2rMeaNI/QwTqPOlLz81j889O7OCGEz4Qe7VmZiNlVc3cwWF8nJ9SQ+q/WU+as8eeQb1xfzMVAdUTSE9rU4sTRsBt/TmDKwklFiLTlL3fOuLxELfN0btKCfU6KwR0TjHPWJ8n3eGqn1gu2nEqiMkiDWpb3HcNf1IrUslEwxvk=
+Prime2: 83qqpATU2Cun88gwYvN4TjjIzpWOk08z/fZPsluC03LVmLuIUga4NO4xNQeZokNfw4lzNm6fp96mp0XWkjSKousrruAQSVDcZleSSuHCgRZM3FhEBXpjndttL3VJTfMZ0V90kmBKAotdvsErfJ6S97td31uEZQgfH92Zh4w6f6s=
+Exponent1: 6ddRHAJXH91kTCw9I4vtIZRU16Mo/cQpjwwXYB1QbKeCWfFLJ+wDOePeNlCHjFuh30rbOU/WBdu7vrKt5uE57zMDCXdfYOBp1MtTG7LSe20tdq4YYVjhudiu9Aeq63Ian+IoYZDSYYgFfnQHv+jVWl7YVFyz1Q5QCqJSwOOKxOE=
+Exponent2: Qd6Tv5/W/UyCOX+VJ4/6oh7WpJztX4jz5eb3FKeRMydEBffmH1rWBuvRwCj4NV/Izpum4bj31HB14ZcRP6ibQQwiW0Me5NbNaZqTZ1LATi/8RzhR3rGHtbMhTM+ML1xvRadvYBJQs3OEvxB/dU1pMUAtWznlDXgvA23uFS+ou9U=
+Coefficient: PQtvgI/OxJoaUTKm9sNvVFH1+fWiZ7o3L3rPYuvoVto5VKWAzu/94GpiIJ4fJF/jQsgtliFgrA9V52Uhvp3GbBreQ+J4JhSh/m7RtXVH+AzIP1lzuqBsNLGoyHXcVFhXEkr6JSqgqp26vudTGNTlYPYmJ7+VvRj0QPy8yM0S/PM=
+Created: 20100217065031
+Publish: 20100217065031
+Activate: 20100217065031

+ 5 - 0
src/bin/loadzone/testdata/Kexample.com.+005+33495.key

@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 33495, for example.com.
+; Created: Tue Feb 16 22:50:27 2010
+; Publish: Tue Feb 16 22:50:27 2010
+; Activate: Tue Feb 16 22:50:27 2010
+example.com. IN DNSKEY 256 3 5 AwEAAcOUBllYc1hf7ND9uDy+Yz1BF3sI0m4qNGV7WcTD0WEiuV7IjXgH E36fCmS9QsUxSSOVo1I/FMxI2PJVqTYHkXFBS7AzLGsQYMU7UjBZSotB J6Imt5pXMu+lEDNy8TOUzG3xm7g0qcbWYF6qCEfvZoBtAqi5Rk7Mlrqs 8agxYyMx

+ 13 - 0
src/bin/loadzone/testdata/Kexample.com.+005+33495.private

@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 5 (RSASHA1)
+Modulus: w5QGWVhzWF/s0P24PL5jPUEXewjSbio0ZXtZxMPRYSK5XsiNeAcTfp8KZL1CxTFJI5WjUj8UzEjY8lWpNgeRcUFLsDMsaxBgxTtSMFlKi0Enoia3mlcy76UQM3LxM5TMbfGbuDSpxtZgXqoIR+9mgG0CqLlGTsyWuqzxqDFjIzE=
+PublicExponent: AQAB
+PrivateExponent: ghbLwlIbJwVnN/wLuBvLVssdGzFbBvv7riTGKSM2+i1mr60mrFfIl8ih2TAqYY/O3mSCJgrfgqJR658e1lliW5Cj2WPOXf5543FrZnkANMQb+BIT5sxB37qFTs9IEKTPNi6Jnb/Vwrpc4jws/5hSsw0GDg16pd0i1e6EAA+sKiE=
+Prime1: 7bSbn5GtQ2OemZnUM6EThChrtz1E5QD6BGEMe0dPekb4JxAPuUBDYzYRuRngEfbrlNKtT766cPm/rz++5P6P1w==
+Prime2: 0qFngA/Ox4otSJqTFtLfBjxzkcAwhJuYuGFL9iq2sPSllY1TA9Mcp40rM9Y8PDrxWhVrcP7YSzZzHR0tckgkNw==
+Exponent1: Xx9xT2/KeDc7VphadLa2yqIqSM+57DJx2qLDjenBgls4HtmskSOIVAFlIj+ajVXUfF+6fzkB/wfSj1zhFV5RTQ==
+Exponent2: ifD6f3vayANONMZGniPru4HLjiB3peDg25+cx9KhYrJV3uN3AoI3ueNR79jWCfvwJDby7kV4EYnPSbnaEYX9cQ==
+Coefficient: WEzY+OoLGFAFJ1o3XopzUxd6dndcDE6yqqz8Wadt/YTOD1mUskJHLxJFsPN7tpkW28VOjxJo6Ypd9GNt/DPyJQ==
+Created: 20100217065027
+Publish: 20100217065027
+Activate: 20100217065027

+ 5 - 0
src/bin/loadzone/testdata/Ksql1.example.com.+005+12447.key

@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 12447, for sql1.example.com.
+; Created: Tue Feb 16 22:50:41 2010
+; Publish: Tue Feb 16 22:50:41 2010
+; Activate: Tue Feb 16 22:50:41 2010
+sql1.example.com. IN DNSKEY 256 3 5 AwEAAdYdRhBAEY67R/8G1N5AjGF6asIiNh/pNGeQ8xDQP13JN2lo+sNq WcmpYNhuVqRbLB+mamsU1XcCICSBvAlSmfz/ZUdafX23knArTlALxMms pcfdpqun3Yr3YYnztuj06rV7RqmveYckWvAUXVYMSMQZfJ305fs0dE/x LztL/CzZ

+ 13 - 0
src/bin/loadzone/testdata/Ksql1.example.com.+005+12447.private

@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 5 (RSASHA1)
+Modulus: 1h1GEEARjrtH/wbU3kCMYXpqwiI2H+k0Z5DzENA/Xck3aWj6w2pZyalg2G5WpFssH6ZqaxTVdwIgJIG8CVKZ/P9lR1p9fbeScCtOUAvEyaylx92mq6fdivdhifO26PTqtXtGqa95hyRa8BRdVgxIxBl8nfTl+zR0T/EvO0v8LNk=
+PublicExponent: AQAB
+PrivateExponent: 0hy3/IpisGYoKKNTkSZWm/G9gfSAmKAIxPkBDabOCALFVbOnIMzkf3iviLP+Yhr2Gbj9BUfUkoyLbkfBdoSQhmB15cHjHH7vXcID8g/AKfMREcEPMSkLjAIf4uEDH2VfRbyLIj2xtYyAjnX4Fnt/10zsQjsUR42pPnIUT5PL6AE=
+Prime1: /ChBaJJbOech6asDqs30EronUFotk2+Pe2tmuEZX4aA8vRHiDyl4r+1yoYk2P0gLdq239rNKHTMwaOFCHOlBoQ==
+Prime2: 2WCZ1TkQtp/CW1yWNkiKj+i976naPNJmjjmQnYeOlukcH41YSy0L0ZztSw9u67U0x5tIC6ydZy56RtpGV+KQOQ==
+Exponent1: 6yeniBwlU2SHreC8dMfI/MX57+eJZVu+1XyduPBw+It02WYaCcXFNVwdcSQDIRTRDAaJ71nYnk6ksMqR22B0wQ==
+Exponent2: sXtq/qnCGKnmIXw99QJTh95KvhSbaE+NhpA/oC8e395ipOxd67tSzAlpwYBPW0ovVs5VC5sbRTSwh4sOJhGJGQ==
+Coefficient: m6v0A9f7BDihWDrynwaksvJPlYjvWepeav9TcHbpd2rSsby+YYwRHDAgqjBqprn7ckCN7CC49Itelvb7dQNSwg==
+Created: 20100217065041
+Publish: 20100217065041
+Activate: 20100217065041

+ 5 - 0
src/bin/loadzone/testdata/Ksql1.example.com.+005+33313.key

@@ -0,0 +1,5 @@
+; This is a key-signing key, keyid 33313, for sql1.example.com.
+; Created: Tue Feb 16 22:50:34 2010
+; Publish: Tue Feb 16 22:50:34 2010
+; Activate: Tue Feb 16 22:50:34 2010
+sql1.example.com. IN DNSKEY 257 3 5 AwEAAbaKDSa9XEFTsjSYpUTHRotTS9Tz3krfDucugW5UokGQKC26QlyH XlPTZkC+aRFUs/dicJX2kopndLcnlNAPWiKnKtrsFSCnIJDBZIyvcKq+ 9RXmV3HK3bUdHnQZ88IZWBRmWKfZ6wnzHo53kdYKAemTErkztaX3lRRP LYWpxRcDPEjysXT3Lh0vfL5D+CIO1yKw/q7C+v6+/kYAxc2lfbNE3Hpk lSuF+dyX4nXxWgzbcFuLz5Bwfq6ZJ9RYe/kNkA0uMWNa1KkGeRh8gg22 kgD/KT5hPTnpezUWLvoY5Qc7IB3T0y4n2JIwiF2ZrZYVrWgDjRWAzGsx JiJyjd6w2k0=

+ 13 - 0
src/bin/loadzone/testdata/Ksql1.example.com.+005+33313.private

@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 5 (RSASHA1)
+Modulus: tooNJr1cQVOyNJilRMdGi1NL1PPeSt8O5y6BblSiQZAoLbpCXIdeU9NmQL5pEVSz92JwlfaSimd0tyeU0A9aIqcq2uwVIKcgkMFkjK9wqr71FeZXccrdtR0edBnzwhlYFGZYp9nrCfMejneR1goB6ZMSuTO1pfeVFE8thanFFwM8SPKxdPcuHS98vkP4Ig7XIrD+rsL6/r7+RgDFzaV9s0TcemSVK4X53JfidfFaDNtwW4vPkHB+rpkn1Fh7+Q2QDS4xY1rUqQZ5GHyCDbaSAP8pPmE9Oel7NRYu+hjlBzsgHdPTLifYkjCIXZmtlhWtaAONFYDMazEmInKN3rDaTQ==
+PublicExponent: AQAB
+PrivateExponent: iT1H3/10tCTyEbtGXmyYrD2nAOeNFKuZ79Q2ObZl+3cfzimApUKdd9azxS+jnQUa/X7EeOtWh7p6tQ2MQ9WXBgC7JrditxcQU+Ui7OcmhSlm6N0yl3pXsEjBUbcFXsRhRY0hUKl1nhhsu95IBi2l/G+4HwgypSJ8sjVJW3ollUNxjqXZK142xLkHML+eHxOVGc6UB73Fx3ig4b6dOxXMmqsi0FUqxtabGQmZXhMxDrWZfCymjhLaUnHac79lDZA9/6onw4m3VI2mKaDuGMa4Y/ODZbz4oHbVgnYfGFMUf/oMiOoq9gRZVHe2ln/P3hyBBllEQnz8sxjh0MOFriXsIQ==
+Prime1: 8J2V8yqXmA3QArlX8Kf0PZalCzq4HNtS5bkRnhB7ajAZWNkPoGSEw+bCbbqdbb3QBU43KqWITmTK1jjWZf3pAQNLfUBQ06KEkEFUYk1yXuDMitl06Va6l548X3oZw0s8blCKrb4B1LzGVf/o/8x1779PEY+x6fOuEpviCFcaRCU=
+Prime2: wjXeP5XvdIs/A+z6CtG9GZGDmZmTegTcJXb3AX2rYm95mxs+0UANv3pPtHuWA9BdC1nxg8AtPZOzg/hNJPHEvVd+68hhKkV86bOTwZ6loYBox8vUUTL2qbmXE3s555iO9jOPwRsh2KoytULqWkkES3Dh8LrvvYKwlvWKIkvmEQk=
+Exponent1: 4hOe1Zg6UXMA895Dw2l7cfa+Yhus6+gjLpdB91sTKoXA+xsPtKtdl1eVbVY/HuKOtr1z1g0sUkQf1UIYKEJ3EC2RW0D38LGtjoDjkW2lPYJIjVmeoLONpHHX1fm6hSWGxTvF4VM7EzC/xgQqX1Yzpa0B1MVH7EK6Vt/CdAWrN0U=
+Exponent2: X7hHIxXWIJ3k4B1zm9OGHU0ADLuJ2XD9xCVfVsfGqcyBpjYGfwHQBNjW4gCrjpOq2EZrZ+FXKutaZigCdbwHmL7AGpv3b+sxxsmwgJSd0/zDJ/5JVgAFXN/RG1P31TL2+1eseaPSycQRHA+wC/HDAR/Q7GJmeQQp3y2D+KVp7mk=
+Coefficient: hiCiGpCuLuUba0z7dpgFSeCk0EWBvrMKR4bI01mgHDK878aB+n1/yxn7nUt/Y38vH5qt+g71ZSfNwngacIt8pmSNUGb6SyKfrrytgaL1atErOyWv1iNF6Y7XnCGtW5Hwx6PAns2naKhILA3xfFe+hgWDC+pFa7CA5Znf65+kvzI=
+Created: 20100217065034
+Publish: 20100217065034
+Activate: 20100217065034

+ 13 - 0
src/bin/loadzone/testdata/README

@@ -0,0 +1,13 @@
+# generate keys for test zones (already done)
+dnssec-keygen example.com
+dnssec-keygen -fk example.com
+dnssec-keygen sql1.example.com
+dnssec-keygen -fk sql1.example.com
+
+# sign the test zones
+dnssec-signzone -S sql1.example.com
+dnssec-signzone -Sg example.com
+
+# load the zone files into the on-disk database
+../b10-loadzone example.com.signed
+../b10-loadzone sql1.example.com.signed

+ 2 - 0
src/bin/loadzone/testdata/dsset-subzone.example.com.

@@ -0,0 +1,2 @@
+subzone.example.com.	IN DS 40633 5 1 3E56C0EA92CF529E005A4B62979533350492F105
+subzone.example.com.	IN DS 40633 5 2 AA8D4BD330C68BFB4D785894DDCF6B689CE9873C4A3801F57A5AA3FE 17925B8C

+ 26 - 0
src/bin/loadzone/testdata/example.com

@@ -0,0 +1,26 @@
+$TTL 3600
+@    SOA master.example.com. admin.example.com. 1234 3600 1800 2419200 7200
+        	NS dns01.example.com.
+        	NS dns02.example.com.
+		NS dns03.example.com.
+                MX 10 mail.example.com.
+                MX 20 mail.subzone.example.com.
+www		A 192.168.1.1
+mail            A 192.168.10.10
+foo		CNAME cnametest.flame.org.
+cname-int	CNAME www.example.com.
+cname-ext	CNAME www.sql1.example.com.
+dns01           A 192.168.2.1
+dns02           A 192.168.2.2
+dns03           A 192.168.2.3
+subzone		NS ns1.subzone.example.com.
+subzone		NS ns2.subzone.example.com.
+ns1.subzone	A 192.168.3.1
+ns2.subzone	A 192.168.3.2
+*.wild		A 192.168.3.2
+dname		DNAME sql1.example.com.
+
+$ORIGIN sql1.example.com.
+sql1.example.com.		NS dns01.example.com.
+		NS dns02.example.com.
+		NS dns03.example.com.

+ 290 - 0
src/bin/loadzone/testdata/example.com.signed

@@ -0,0 +1,290 @@
+; File written on Sat Feb 20 01:45:38 2010
+; dnssec_signzone version 9.7.0
+example.com.		3600	IN SOA	master.example.com. admin.example.com. (
+					1234       ; serial
+					3600       ; refresh (1 hour)
+					1800       ; retry (30 minutes)
+					2419200    ; expire (4 weeks)
+					7200       ; minimum (2 hours)
+					)
+			3600	RRSIG	SOA 5 2 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					KUun66Qaw36osk2BJS6U1fAy3PPDkNo2QK4m
+					eGNbDBY8q8b+f2o+IXJ14YCvssGl1ORW0CcL
+					nDRxssnk8V/Svmj5iFhO+8HC2hnVBdi2zewv
+					dVtwRb+lWwKN7pkXXwuy6g1t9WCd/j5FCc/w
+					gxqtZUTPb6XgZcnHrORDMOTqLs4= )
+			3600	NS	dns01.example.com.
+			3600	NS	dns02.example.com.
+			3600	NS	dns03.example.com.
+			3600	RRSIG	NS 5 2 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					ClcrfjkQZUY5L6ZlCkU3cJHzcrEGrofKSVee
+					oeZ+w6yeEowFNVXs2YBo3tom53DiCrdD9rs3
+					feVSLGW5rjsz/O6lDuomgQG+EVSnWa7GTIPB
+					Xj1BmDXXp3XxeldYmhf4UzaN5BA+RUA5E8NC
+					hNKuNNof76j2S9tilfN/kvpy4fw= )
+			3600	MX	10 mail.example.com.
+			3600	MX	20 mail.subzone.example.com.
+			3600	RRSIG	MX 5 2 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					ooh3/uAdqf/BFxqhncQrCvepKJbWf8235WLD
+					93m3TwJoxSLC5SsD6SGXa49wWeWxBpjhargR
+					aezN7JQ1T6RKMUQcbCz3Uoku2gznPIsUvJEU
+					w+vFz2hh5FUE2OVoiD5UL34PsyjpMu7XBjNY
+					FUK564QHflpeRpuLoYyxexgSGmY= )
+			7200	NSEC	cname-ext.example.com. NS SOA MX RRSIG NSEC DNSKEY
+			7200	RRSIG	NSEC 5 2 7200 20100322084538 (
+					20100220084538 33495 example.com.
+					KxuVaPPKNPJzr/q+cJPiNlkHVTQK0LVsgTbS
+					qruXQc25lAd0wn5oKUtxL1bEAchHkfA8eLzc
+					YCj2ZqqAv9OJubw53mfskTad7UHs4Uj2RTrI
+					sNGMCiZGgOpvNb9JcWpQtoyXVT1uNse+Qsbe
+					ir0eyeYIufUynFU041jtNrlJMio= )
+			3600	DNSKEY	256 3 5 (
+					AwEAAcOUBllYc1hf7ND9uDy+Yz1BF3sI0m4q
+					NGV7WcTD0WEiuV7IjXgHE36fCmS9QsUxSSOV
+					o1I/FMxI2PJVqTYHkXFBS7AzLGsQYMU7UjBZ
+					SotBJ6Imt5pXMu+lEDNy8TOUzG3xm7g0qcbW
+					YF6qCEfvZoBtAqi5Rk7Mlrqs8agxYyMx
+					) ; key id = 33495
+			3600	DNSKEY	257 3 5 (
+					AwEAAe5WFbxdCPq2jZrZhlMj7oJdff3W7syJ
+					tbvzg62tRx0gkoCDoBI9DPjlOQG0UAbj+xUV
+					4HQZJStJaZ+fHU5AwVNT+bBZdtV+NujSikhd
+					THb4FYLg2b3Cx9NyJvAVukHp/91HnWuG4T36
+					CzAFrfPwsHIrBz9BsaIQ21VRkcmj7DswfI/i
+					DGd8j6bqiODyNZYQ+ZrLmF0KIJ2yPN3iO6Zq
+					23TaOrVTjB7d1a/h31ODfiHAxFHrkY3t3D5J
+					R9Nsl/7fdRmSznwtcSDgLXBoFEYmw6p86Acv
+					RyoYNcL1SXjaKVLG5jyU3UR+LcGZT5t/0xGf
+					oIK/aKwENrsjcKZZj660b1M=
+					) ; key id = 4456
+			3600	RRSIG	DNSKEY 5 2 3600 20100322084538 (
+					20100220084538 4456 example.com.
+					SOR9XmFwTECrb7GH4WWybovFVkzsV3pqtz5d
+					Dp7L24nx/v+MDJzWhzczWh7i4P8Z2BCRnzqU
+					V7H9RRCLv/o9utDREFsYf5hBzidJcjUpyMQ3
+					cqGh9obIk/QRf0JjorUNOuAENppIjOSJtzk4
+					K7WYp+KIwrjjPeDEp2e5l+9EuBspowOD5R+P
+					QxkzNxbiGqo4UIZ0HqmJccpAykd8OCRLUGv0
+					EqZWVymTJ7us5uoVS6TofP3fmtQSXUlB2GVT
+					b0Q3UW2PdH332nU588Q1wQTf3xa8FI7rJD6C
+					LVC0OSI7lWpWVID1X4++KIDVGzwcNj8W+ilC
+					RHBbdEIRYuE0AhpMDQ== )
+			3600	RRSIG	DNSKEY 5 2 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					OgEjTmMOo4Evt3AAmAN1WufYuXaPUP2dGd/B
+					96K6OVdE5xDWnMHz1cO2tzkn+E6Y4oJl1EBg
+					ShZguhchu6EA6ppSqsgQCKlkVgf+hvkBqbRq
+					+1gmotrCrI5P3HzkgiqF71adijidvXQal3BI
+					zqKlYMTaYbdxYVlTjOfhk6weSPM= )
+cname-ext.example.com.	3600	IN CNAME www.sql1.example.com.
+			3600	RRSIG	CNAME 5 3 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					bGPIuZilyygvTThK4BrdECuaBcnZUgW/0d09
+					iN2CrNjckchQl3dtbnMNirFsVs9hShDSldRN
+					lQpiAVMpnPgXHhReNum7jmX6yqIH6s8GKIo9
+					1zr3VL/ramlezie5w4MilDHrxXLK2pb8IHmP
+					+ZHivQ2EtdYQZgETWBWxr5FDfwk= )
+			7200	NSEC	cname-int.example.com. CNAME RRSIG NSEC
+			7200	RRSIG	NSEC 5 3 7200 20100322084538 (
+					20100220084538 33495 example.com.
+					inWsFwSDWG7TakjwbUTzTRpXz0WifelA5Kn3
+					ABk6BVirIPmd+yQoNj2QZBDFAQwhnLPlNws2
+					Oo4vgMsBMyx1Fv5eHgMUuCN3DUDaLlzlPtUb
+					42CjOUa+jZBeTV/Hd7WZrirluASE1QFDprLd
+					SSqoPPfAKvN3pORtW7y580dMOIM= )
+cname-int.example.com.	3600	IN CNAME www.example.com.
+			3600	RRSIG	CNAME 5 3 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					U1wjt0XY9xjTwvUmWSUcfLGMhCjfX2ylWfHr
+					ycy50x2oxcK9z94E1ejen9wDTIEBSGYgi6wp
+					Z8RK0+02N1DWTGpDqNXd7aFRfDrWQJ/q/XJH
+					Dx0vlcmhkWhrT82LBfKxkrptOzchuSo/c0mp
+					K+mpiIMc1VOwY+yuQ2ALfcD6EHw= )
+			7200	NSEC	dname.example.com. CNAME RRSIG NSEC
+			7200	RRSIG	NSEC 5 3 7200 20100322084538 (
+					20100220084538 33495 example.com.
+					rbV+gaxfrsoha59NOLF4EFyWQ+GuFCVK/8D7
+					7x1atan3HNlXBlZ1smgudKTaJ3CtlobIDt0M
+					EdPxY1yn2Tskw/5mlP1PWf8oaP3BwGSQdn4g
+					LI8+sMpNOPFEdXpxqxngm2F6/7fqniL1QuSA
+					QBEdO+5UiCAgnncPmAsSJg3u1zg= )
+dname.example.com.	3600	IN DNAME sql1.example.com.
+			3600	RRSIG	DNAME 5 3 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					ae8U47oaiwWdurkSyzcsCAF6DxBqjukizwF7
+					K7U6lQVMtfoUE14oiAqfj1fjH8YLDOO/Hd1t
+					wrd/u0vgjnI1Gg32YTi7cYOzwE912SV1u2B/
+					y0awaQKWPBwOW0aI7vxelt1vMUF81xosiQD0
+					4gOIdDBTqbHKcDxum87iWbhk4Ug= )
+			7200	NSEC	dns01.example.com. DNAME RRSIG NSEC
+			7200	RRSIG	NSEC 5 3 7200 20100322084538 (
+					20100220084538 33495 example.com.
+					c21Fff2D8vBrLzohBnUeflkaRdUAnUxAFGp+
+					UQ0miACDCMOFBlCS9v9g/2+orOnKfd3l4vyz
+					55C310t8JXgXb119ofaZWj2zkdUe+X8Bax+s
+					MS0Y5K/sUhSNvbJbozr9UYPdvjSVBiWgh3s9
+					fsb+etKq9uFukAzGU/FuGYpO0r0= )
+dns01.example.com.	3600	IN A	192.168.2.1
+			3600	RRSIG	A 5 3 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					NIawlZLk8WZAjNux7oQM2mslfW52OZFFkWt+
+					+7FHu2SU98XqEeKfCMnpgtWe5T8Nr9cS8df9
+					01iEOJoWQzGTEaHYUBtEhsSjBVn7mKp3fz64
+					73a2xxy75SUKZ0rxjNXSZ8Q5rnFmkX0HTH2S
+					g51mtjH6aC2pfheQnA2t193BnSg= )
+			7200	NSEC	dns02.example.com. A RRSIG NSEC
+			7200	RRSIG	NSEC 5 3 7200 20100322084538 (
+					20100220084538 33495 example.com.
+					EkyeshmMNP9xiAz6mDFDIwksTdmkF9zsFzLu
+					VKAgK6eUk7St6tp5PSvjA8nWol0vdvvz4LK8
+					5a4ffTFEiNRyvWeYP2vOhEkyDcrwuCd8Vc3j
+					h/8Sm1Js+nX7hJStrZGFvp2TWPpt9nKH5p3M
+					xXvTb/YVurnue0xSeFAE17O3+I0= )
+dns02.example.com.	3600	IN A	192.168.2.2
+			3600	RRSIG	A 5 3 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					XJtVMbUIRE0mk6Hn/Nx6k36jaxaBDPK2/IYB
+					6vCQjJETz6gW4T6q/H/eY9/Lsw5iYPFhoBRD
+					xT4XFj575t98kELXnJe1WhuMbRPlOhyOjxkL
+					ECaUne/sbFPOtbGFx9ohuojI0RgxxZiCFaO8
+					wJuv6nfPuzmlLajWS6z9NZeOMIk= )
+			7200	NSEC	dns03.example.com. A RRSIG NSEC
+			7200	RRSIG	NSEC 5 3 7200 20100322084538 (
+					20100220084538 33495 example.com.
+					imBNTMB3sPU4kblcaAH6V7lCVt5xgtAybi3D
+					A/SbLEulLaV2NE6vcoEn/AieaM4mOJicQnUD
+					j/H+1hSEhzxU2tRM8zfVlvztxQWn6eh7ZR4m
+					KfNDSvRUGU9ykhpwMyC7wjOt1j5bcSA/OTnL
+					RAilslnJyOM4bSaxVEFo8YPjncY= )
+dns03.example.com.	3600	IN A	192.168.2.3
+			3600	RRSIG	A 5 3 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					Ubrcm1H+F6m8khle7P9zU8eO+Jtuj+1Vx1MM
+					5KAkmZPJwQe9uTcoCpQa6DXOGG9kajDTnNN1
+					Be1gkZuJDTZJG4SmJLXLbNY3RDnxpGmWta3q
+					s/VgDq78/YM8ropt1/s7YKyrCfGE2ff+FUB0
+					mLObiG01ZV2gu5HJzgE7SEWLEiI= )
+			7200	NSEC	foo.example.com. A RRSIG NSEC
+			7200	RRSIG	NSEC 5 3 7200 20100322084538 (
+					20100220084538 33495 example.com.
+					nn829Xw5CJFnPHwI9WHeT5epQv+odtCkHnjl
+					PFGoPTLOyiks+041UmMqtq3uiSp4d2meMSe9
+					UuDvoROT0L6NTtQQvVqiDhTn0irTFw1uw7fO
+					8ZTG7eyu6Ypfz0+HvfbNvd4kMoD2OTgADRXP
+					VsCTwK+PBOIIG9YTEQfl8pCqW5g= )
+foo.example.com.	3600	IN CNAME cnametest.flame.org.
+			3600	RRSIG	CNAME 5 3 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					DSqkLnsh0gCeCPVW/Q8viy9GNP+KHmFGfWqy
+					VG1S6koBtGN/VQQ16M4PHZ9Zssmf/JcDVJNI
+					hAChHPE2WJiaPCNGTprsaUshf1Q2vMPVnkrJ
+					KgDY8SVRYMptmT8eaT0gGri4KhqRoFpMT5OY
+					fesybwDgfhFSQQAh6ps3bIUsy4o= )
+			7200	NSEC	mail.example.com. CNAME RRSIG NSEC
+			7200	RRSIG	NSEC 5 3 7200 20100322084538 (
+					20100220084538 33495 example.com.
+					RTQwlSqui6StUYye1KCSOEr1d3irndWFqHBp
+					wP7g7n+w8EDXJ8I7lYgwzHvlQt6BLAxe5fUD
+					i7ct8M5hXvsm7FoWPZ5wXH+2/eJUCYxIw4ve
+					zKMkMwBP6M/YkJ2CMqY8DppYf60QaLDONQAr
+					7AcK/naSyioeI5h6eaoVitUDMso= )
+mail.example.com.	3600	IN A	192.168.10.10
+			3600	RRSIG	A 5 3 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					EG78Rr7lI99x8fCg+nSTGJtxyK9rlnmbHB+P
+					bn6UX9QdyYvWCj3/wU3Rz2z8E/piV+XrtLNQ
+					hrqOkaM1XaxPg/DgiZ275uPJRObLFgvuCMXZ
+					cBsJ3kt4zw+N6RjtjKO9WkvheRq6TfiiLB+O
+					POOlueqWagMDXx1Pjmbkyv7BNAo= )
+			7200	NSEC	sql1.example.com. A RRSIG NSEC
+			7200	RRSIG	NSEC 5 3 7200 20100322084538 (
+					20100220084538 33495 example.com.
+					lSS6eNZVy1oAK/+54kAc96NJY0z0guJDmV5u
+					dENBCldWli7MkcO5SrySx48DaYPpOfEv2ulS
+					ItW7Qn/REMbcMb8g4IYxQK4GRqnlmgExdTqZ
+					l/3oQbJCXCvBW4nhtYreeBaKXCw2yIBogoBD
+					1Uej/lMZ48o3oaxpC+SrC76gN+Q= )
+sql1.example.com.	3600	IN NS	dns01.example.com.
+			3600	IN NS	dns02.example.com.
+			3600	IN NS	dns03.example.com.
+			3600	DS	33313 5 1 (
+					FDD7A2C11AA7F55D50FBF9B7EDDA2322C541
+					A8DE )
+			3600	DS	33313 5 2 (
+					0B99B7006F496D135B01AB17EDB469B4BE9E
+					1973884DEA757BC4E3015A8C3AB3 )
+			3600	RRSIG	DS 5 3 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					dIqZKvpkJN1l92SOiWgJh3KbjErIN+EfojMs
+					m4pEdV5xQdZwj6DNNEu6Kw4rRwdvrZIu0Tyq
+					Pr3jSJb7o6R7vZgZzmLfVV/ojQah7rwuYHCF
+					cfyZ4JyK2311fMhRR1QAvMsdcjdyA1XC140C
+					m6AnL3cH5rh/KUks/0ec3Ca7GNQ= )
+			7200	NSEC	subzone.example.com. NS DS RRSIG NSEC
+			7200	RRSIG	NSEC 5 3 7200 20100322084538 (
+					20100220084538 33495 example.com.
+					k9FRdFyk/cPdkmmaoZbGZPpzIzfbFWQ3QCHd
+					2qhJa0xAXaEOT/GBL6aFqx9SlunDu2wgES+T
+					o5fWPZGi4NzWpp6c5t27rnATN/oCEQ/UYIJK
+					mWbqrXdst0Ps5boznk7suK2Y+km31KxaIf3f
+					Dd/T3kZCVsR0aWKRRRatPb7GfLw= )
+ns1.subzone.example.com. 3600	IN A	192.168.3.1
+ns2.subzone.example.com. 3600	IN A	192.168.3.2
+subzone.example.com.	3600	IN NS	ns1.subzone.example.com.
+			3600	IN NS	ns2.subzone.example.com.
+			3600	DS	40633 5 1 (
+					3E56C0EA92CF529E005A4B62979533350492
+					F105 )
+			3600	DS	40633 5 2 (
+					AA8D4BD330C68BFB4D785894DDCF6B689CE9
+					873C4A3801F57A5AA3FE17925B8C )
+			3600	RRSIG	DS 5 3 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					rARTxwVxMTN64iK8NWOW7FjXLdIJBpAik5BZ
+					TcmqOAp16v3ijRC4UZfs6LFHMXHwIPHJlggx
+					mrDDeJtSgNAs82ZR8/L8T80tHL7cythf3OFA
+					t5VDY2sQKEBPun1bRhi4g0KAbd5MURv9kawX
+					MCxNuSkIAZpzZMHdMo7jLxHLsSs= )
+			7200	NSEC	*.wild.example.com. NS DS RRSIG NSEC
+			7200	RRSIG	NSEC 5 3 7200 20100322084538 (
+					20100220084538 33495 example.com.
+					Oe2kgIhsLtPJ4+lDZDxznV8/vEVoXKOBFN9l
+					wWyebaKa19BaSXlQ+YVejmulmKDDjEucMvEf
+					uItfn6w7bnU+DzOLk5D1lJCjwDlKz8u3xOAx
+					16TiuQn4bgQAOiFtBQygmGGqO3BVpX+jxsmw
+					7eH3emofy8uUqr/C4aopnwuf28g= )
+*.wild.example.com.	3600	IN A	192.168.3.2
+			3600	RRSIG	A 5 3 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					FdO+UWONgtLKFxUzzygGunw67F9y8SzsP7yO
+					LEYVJclRR8X3Ii62L0gtQHq2y0TcKsXttRsD
+					6XY+tM5P/pgXlTNi7Bk4Fgb0PIDPjOsfT4Dr
+					S80kWn0YbinM/4/FA1j5ru5sTTboOY5UGhvD
+					noA9ogNuQQYb2/3wkoH0PrA2Q/0= )
+			7200	NSEC	www.example.com. A RRSIG NSEC
+			7200	RRSIG	NSEC 5 3 7200 20100322084538 (
+					20100220084538 33495 example.com.
+					OoGYslRj4xjZnBuzgOqsrvkDAHWycmQzbUxC
+					RmgWnCbXiobJK7/ynONH3jm8G3vGlU0lwpHk
+					hNs6cUK+6Nu8W49X3MT0Xksl/brroLcXYLi3
+					vfxnYUNMMpXdeFl6WNNfoJRo90F/f/TWXACl
+					RrDS29qiG3G1PEJZikIxZsZ0tyM= )
+www.example.com.	3600	IN A	192.168.1.1
+			3600	RRSIG	A 5 3 3600 20100322084538 (
+					20100220084538 33495 example.com.
+					qyFyyV/mE8x4pdhudr5iycwhDsva31MzwO1k
+					BR+bDKvzJg8mN8KxlPZrOlNNUhd3YRXQVwie
+					MyxOTWRPXoxrNEDkNwimXkfe3rrHY7ibV9eN
+					S4OIBUjb44VjCNr9CmQSzfuQ2yxO2r+YIuPY
+					HRCjieD4xh6t9ay4IaCN/tDAJ+Q= )
+			7200	NSEC	example.com. A RRSIG NSEC
+			7200	RRSIG	NSEC 5 3 7200 20100322084538 (
+					20100220084538 33495 example.com.
+					ZLZlSVBa2oe4U+7SZASnypP2VkI5gg1/1cVG
+					qYUvfYNIUkcVMWDgn7DZCfpmo+2vdlV/4VhA
+					c+sjDd+X+e57XGnW8+lqZHvG6NMMhmSGmeAT
+					D3D+8lEJJGo0dxoN4rHJQyp/eT2S4nChz+D/
+					ze+YRagYxGF7pXm9zcrw3kKZGTs= )

+ 7 - 0
src/bin/loadzone/testdata/sql1.example.com

@@ -0,0 +1,7 @@
+$ORIGIN sql1.example.com.
+$TTL 3600
+@	SOA master.example.com. admin.example.com. 678 3600 1800 2419200 7200
+	NS dns01.example.com.
+	NS dns02.example.com.
+	NS dns03.example.com.
+www	3600 IN A 192.168.2.2

+ 88 - 0
src/bin/loadzone/testdata/sql1.example.com.signed

@@ -0,0 +1,88 @@
+; File written on Sat Feb 20 01:45:36 2010
+; dnssec_signzone version 9.7.0
+sql1.example.com.	3600	IN SOA	master.example.com. admin.example.com. (
+					678        ; serial
+					3600       ; refresh (1 hour)
+					1800       ; retry (30 minutes)
+					2419200    ; expire (4 weeks)
+					7200       ; minimum (2 hours)
+					)
+			3600	RRSIG	SOA 5 3 3600 20100322084536 (
+					20100220084536 12447 sql1.example.com.
+					oakulfyljL/RAKgCKXEZ3KsG8BJj5WG4JK4m
+					oWFB6c9OKem6jIk8hKP2XlUVXFuOYJlRdIM4
+					KicmR2GAK+5jJp6z5ShssstYTXo3QosVm6oC
+					KumuFeLFHzcjfqP1D+F9NsvHldJIBnS/4ebP
+					kmR5OENyCZXQF5HmN2awIj4CLjE= )
+			3600	NS	dns01.example.com.
+			3600	NS	dns02.example.com.
+			3600	NS	dns03.example.com.
+			3600	RRSIG	NS 5 3 3600 20100322084536 (
+					20100220084536 12447 sql1.example.com.
+					0CL8noy0NSgoWwuKd+Dc6vyIIw2BrAEBx0IJ
+					zcSB6GlB25x/zjEd6AJG0be13HN6jOaTX8iW
+					TuCVrEYuXg76V+M4EvTZHjEScj0az74TrDv4
+					Vdo459paGKCX9B8NLJW1mW4fzZrrXQ8jmBEZ
+					eS91Q5rJrO+UKJEuUz3LYdTPvao= )
+			7200	NSEC	www.sql1.example.com. NS SOA RRSIG NSEC DNSKEY
+			7200	RRSIG	NSEC 5 3 7200 20100322084536 (
+					20100220084536 12447 sql1.example.com.
+					v71CgdTYccCiTqfRcn6HsvISQa8ruvUfCKtp
+					wym0RW/G27xlZn8otj2IMtWwkLxti8Rqqu+P
+					TViLaOIbeVfHBcqzAd7U59cAOYoq3ODZx6au
+					iE3C23HAKqUavKcP7Esaajm1cbcWy6Kyie4C
+					AZc8M7EeKxgkXMKJGqBQzF+/FOo= )
+			3600	DNSKEY	256 3 5 (
+					AwEAAdYdRhBAEY67R/8G1N5AjGF6asIiNh/p
+					NGeQ8xDQP13JN2lo+sNqWcmpYNhuVqRbLB+m
+					amsU1XcCICSBvAlSmfz/ZUdafX23knArTlAL
+					xMmspcfdpqun3Yr3YYnztuj06rV7RqmveYck
+					WvAUXVYMSMQZfJ305fs0dE/xLztL/CzZ
+					) ; key id = 12447
+			3600	DNSKEY	257 3 5 (
+					AwEAAbaKDSa9XEFTsjSYpUTHRotTS9Tz3krf
+					DucugW5UokGQKC26QlyHXlPTZkC+aRFUs/di
+					cJX2kopndLcnlNAPWiKnKtrsFSCnIJDBZIyv
+					cKq+9RXmV3HK3bUdHnQZ88IZWBRmWKfZ6wnz
+					Ho53kdYKAemTErkztaX3lRRPLYWpxRcDPEjy
+					sXT3Lh0vfL5D+CIO1yKw/q7C+v6+/kYAxc2l
+					fbNE3HpklSuF+dyX4nXxWgzbcFuLz5Bwfq6Z
+					J9RYe/kNkA0uMWNa1KkGeRh8gg22kgD/KT5h
+					PTnpezUWLvoY5Qc7IB3T0y4n2JIwiF2ZrZYV
+					rWgDjRWAzGsxJiJyjd6w2k0=
+					) ; key id = 33313
+			3600	RRSIG	DNSKEY 5 3 3600 20100322084536 (
+					20100220084536 12447 sql1.example.com.
+					Qg0B5QY31lBa1I76nZ+9PEntoqJSN4s7SYTg
+					7ObKykN5gXfu2COT8Yu5oXRf6NBvDi/b+Ocb
+					rUm+fYdP0SaH2wte+ZYJK0mtSEwailoAR3yH
+					vumOHLPVasnWOG5SmaVVt5BVtszUMm82H3En
+					u5zTkT8CAA4SG9XGG+i642jph10= )
+			3600	RRSIG	DNSKEY 5 3 3600 20100322084536 (
+					20100220084536 33313 sql1.example.com.
+					HbvuqbmpgVRW2sfV9KPjNr4M4SAAIMAdHvxf
+					4KUMVUbGymh0kg404uw58MKhcjJ/3+ySK4DF
+					IiGOYtadmD1LlDxFasQfpCiLPbiDpT87ZIIT
+					ZhNBc6Sbz0xfRdLrByD8blVAyhlp3LXbKeXd
+					peFmQJsVrZMcvSSpV1tT4EN9E0IqM69AsBji
+					4fC+k8PG58gQGPnB21oO6u/HvtTYfTCxXhDg
+					omWggFryvC0JeyRaObjmWcdr8AkbAdAethPC
+					eSvBB/X3UOFhT9nE0wr/oL2t2I9anfBtMufq
+					d5orANOdFJzs6fdwrDcRtaft5cs7BKV8+r42
+					t41mF2LzlMWJ9rp1iw== )
+www.sql1.example.com.	3600	IN A	192.168.2.2
+			3600	RRSIG	A 5 4 3600 20100322084536 (
+					20100220084536 12447 sql1.example.com.
+					DNdVKxB3oBsB14NPoV9WG14Y/g4zMcIXLYnF
+					jj9vRZRZJpAvbTEipiXlayuhOxnqU827OipE
+					TQyeULZmLsqIQ1wK4Fgf+9b5aJ8D85/o4wBk
+					a00X4hZ3MwDPRb4mjuogwBTBg5NRpNSzUfbk
+					PGiav08BFwgg+Efm9veSB05arS0= )
+			7200	NSEC	sql1.example.com. A RRSIG NSEC
+			7200	RRSIG	NSEC 5 4 7200 20100322084536 (
+					20100220084536 12447 sql1.example.com.
+					cJMJhDx/ND7/9j3zhyXe+6eaSsU7ByYpXhJz
+					be+OhjFgH0VasQXq7o1QB3I293UZ+yhkjgXa
+					p+9QtPlraaNaYyTyOMQ42OoxSefJpYz9CME/
+					FI2tsUfyrCnLFxYRNet7sMS0q+hLqxRayuEH
+					DFDp72hHPGLJQ8a7jq4SrIonT50= )

+ 1 - 1
src/lib/python/isc/Makefile.am

@@ -1,4 +1,4 @@
-SUBDIRS = cc Util config
+SUBDIRS = auth cc Util config
 
 
 PY_MODULES=	__init__.py
 PY_MODULES=	__init__.py
 
 

+ 1 - 0
src/lib/python/isc/__init__.py

@@ -1,3 +1,4 @@
+import isc.auth
 import isc.cc
 import isc.cc
 import isc.Util
 import isc.Util
 import isc.config
 import isc.config

+ 6 - 0
src/lib/python/isc/auth/Makefile.am

@@ -0,0 +1,6 @@
+PY_MODULES=	__init__.py master.py sqlite3ds.py
+
+install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(pyexecdir)/isc/auth
+	@(for _foo_ in $(PY_MODULES) ; \
+		do $(INSTALL) -m 0644 $(top_srcdir)/src/lib/auth/python/isc/auth/$$_foo_ $(DESTDIR)$(pyexecdir)/isc/auth/; done)

+ 2 - 0
src/lib/python/isc/auth/__init__.py

@@ -0,0 +1,2 @@
+from isc.auth.master import *
+from isc.auth.sqlite3_ds import *

+ 447 - 0
src/lib/python/isc/auth/master.py

@@ -0,0 +1,447 @@
+# Copyright (C) 2010  Internet Systems Consortium.
+#
+# 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 INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM 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.
+
+import sys, re, string
+
+#########################################################################
+# define exceptions
+#########################################################################
+class MasterFileError(Exception):
+    pass
+
+#########################################################################
+# global variables
+#########################################################################
+maxttl = 0x7fffffff
+defclass = 'IN'
+
+#########################################################################
+# cleanup: removes excess content from zone file data, including comments
+# and extra whitespace
+# input:
+#   line of text
+# returns:
+#   the same line, with comments removed, leading and trailing
+#   whitespace removed, and all other whitespace compressed to
+#   single spaces
+#########################################################################
+decomment = re.compile('\s*(?:;.*)+')
+def cleanup(s):
+    global decomment
+    s = s.strip().expandtabs()
+    s = decomment.sub('', s)
+    return ' '.join(s.split())
+
+#########################################################################
+# records: generator function to return complete RRs from the zone file,
+# combining lines when necessary because of parentheses
+# input:
+#   zonedata as an array of lines
+# yields:
+#   complete RR
+#########################################################################
+def records(data):
+    record = []
+    complete = True
+    paren = 0
+    for line in data:
+        list = cleanup(line).split()
+        for word in list:
+            if paren == 0:
+                left, p, right = word.partition('(')
+                if p == '(':
+                    if left: record.append(left)
+                    if right: record.append(right)
+                    paren += 1
+                else:
+                    record.append(word)
+            else:
+                left, p, right = word.partition(')')
+                if p == ')':
+                    if left: record.append(left)
+                    if right: record.append(right)
+                    paren -= 1
+                else:
+                    record.append(word)
+
+        if paren == 1 or not record:
+            continue
+
+        ret = ' '.join(record)
+        record = []
+        yield ret
+
+#########################################################################
+# pop: remove the first word from a line
+# input: a line
+# returns: first word, rest of the line
+#########################################################################
+def pop(line):
+    list = line.split()
+    first = list[0]
+    rest = ' '.join(list[1:])
+    return first, rest
+
+#########################################################################
+# istype: check whether a string is a known RR type.
+# returns: boolean
+#########################################################################
+rrtypes = set(['a', 'aaaa', 'afsdb', 'apl', 'cert', 'cname', 'dhcid',
+               'dlv', 'dname', 'dnskey', 'ds', 'gpos', 'hinfo', 'hip',
+               'ipseckey', 'isdn', 'key', 'kx', 'loc', 'mb', 'md',
+               'mf', 'mg', 'minfo', 'mr', 'mx', 'naptr', 'ns', 'nsap',
+               'nsap-ptr', 'nsec', 'nsec3', 'nsec3param', 'null',
+               'nxt', 'opt', 'ptr', 'px', 'rp', 'rrsig', 'rt', 'sig',
+               'soa', 'spf', 'srv', 'sshfp', 'tkey', 'tsig', 'txt',
+               'x25', 'wks'])
+def istype(s):
+    global rrtypes
+    if s.lower() in rrtypes:
+        return True
+    else:
+        return False
+
+#########################################################################
+# isclass: check whether a string is a known RR class.  (only 'IN' is
+# supported, but the others must still be recognizable.)
+# returns: boolean
+#########################################################################
+rrclasses = set(['in', 'ch', 'chaos', 'hs', 'hesiod'])
+def isclass(s):
+    global rrclasses
+    if s.lower() in rrclasses:
+        return True
+    else:
+        return False
+
+#########################################################################
+# isname: check whether a string is a valid DNS name.
+# returns: boolean
+#########################################################################
+name_regex = re.compile('[-\w\$\d\/*]+(?:\.[-\w\$\d\/]+)*\.?')
+def isname(s):
+    global name_regex
+    if name_regex.match(s):
+        return True
+    else:
+        return False
+
+#########################################################################
+# isttl: check whether a string is a valid TTL specifier.
+# returns: boolean
+#########################################################################
+ttl_regex = re.compile('[0-9]+[wdhms]?', re.I)
+def isttl(s):
+    global ttl_regex
+    if ttl_regex.match(s):
+        return True
+    else:
+        return False
+
+#########################################################################
+# parse_ttl: convert a TTL field into an integer TTL value
+# (multiplying as needed for minutes, hours, etc.)
+# input:
+#   string
+# returns:
+#   int
+# throws:
+#   MasterFileError
+#########################################################################
+def parse_ttl(s):
+    m = re.match('([0-9]+)(.*)', s)
+    if not m:
+        raise MasterFileError('Invalid TTL: ' + s)
+    ttl, suffix = int(m.group(1)), m.group(2)
+    if suffix.lower() == 'w':
+        ttl *= 604800
+    elif suffix.lower() == 'd':
+        ttl *= 86400
+    elif suffix.lower() == 'h':
+        ttl *= 3600
+    elif suffix.lower() == 'm':
+        ttl *= 60
+    return ttl
+
+#########################################################################
+# directive: handle $ORIGIN, $TTL and $GENERATE directives
+# (currently only $ORIGIN and $TTL are implemented)
+# input:
+#   a line from a zone file
+# returns:
+#   a boolean indicating whether a directive was found
+# throws:
+#   MasterFileError
+#########################################################################
+def directive(s):
+    global origin, defttl, maxttl
+    first, more = pop(s)
+    second, more = pop(more)
+    if re.match('\$origin', first, re.I):
+        if not isname(second):
+            raise MasterFileError('Invalid $ORIGIN')
+        if more:
+            raise MasterFileError('Invalid $ORIGIN')
+        if second[-1] == '.':
+            origin = second
+        else:
+            origin = second + '.' + origin
+        return True
+    elif re.match('\$ttl', first, re.I):
+        if not isttl(second):
+            raise MasterFileError('Invalid $TTL: ' + second)
+        if more:
+            raise MasterFileError('Invalid $TTL statement')
+        defttl = parse_ttl(second)
+        if defttl > maxttl:
+            raise MasterFileError('TTL too high: ' + second)
+        return True
+    elif re.match('\$generate', first, re.I):
+        raise MasterFileError('$GENERATE not yet implemented')
+    else:
+        return False
+
+#########################################################################
+# include: handle $INCLUDE directives
+# input:
+#   a line from a zone file
+# returns:
+#   the parsed output of the included file, if any, or an empty array
+# throws:
+#   MasterFileError
+#########################################################################
+filename=re.compile('[\"\']*([^\'\"]+)[\"\']*')
+def include(s):
+    global origin, defttl, maxttl
+    first, rest = pop(s)
+    if re.match('\$include', first, re.I):
+        m = filename.match(rest)
+        if m:
+            file = m.group(1)
+            return parse(file)
+
+#########################################################################
+# four: try parsing on the assumption that the RR type is specified in
+# field 4, and name, ttl and class are in fields 1-3
+# are all specified, with type in field 4
+# input:
+#   a record to parse, and the most recent name found in prior records
+# returns:
+#   empty list if parse failed, else name, ttl, class, type, rdata
+#########################################################################
+def four(record, curname):
+    ret = ''
+    list = record.split()
+    if len(list) <= 4:
+        return ret
+    if istype(list[3]):
+        if isclass(list[2]) and isttl(list[1]) and isname(list[0]):
+            name, ttl, rrclass, rrtype = list[0:4]
+            rdata = ' '.join(list[4:])
+            ret = name, ttl, rrclass, rrtype, rdata
+    return ret
+
+#########################################################################
+# three: try parsing on the assumption that the RR type is specified in
+# field 3, and one of name, ttl, or class has been omitted
+# input:
+#   a record to parse, and the most recent name found in prior records
+# returns:
+#   empty list if parse failed, else name, ttl, class, type, rdata
+#########################################################################
+def three(record, curname):
+    global defttl, defclass
+    ret = ''
+    list = record.split()
+    if len(list) <= 3:
+        return ret
+    if istype(list[2]) and not istype(list[1]):
+        if isclass(list[1]) and not isttl(list[0]) and isname(list[0]):
+            rrclass = list[1]
+            ttl = defttl
+            name = list[0]
+        elif not isclass(list[1]) and isttl(list[1]) and isname(list[0]):
+            rrclass = defclass
+            ttl = parse_ttl(list[1])
+            name = list[0]
+        elif curname and isclass(list[1]) and isttl(list[0]):
+            rrclass = defclass
+            ttl = parse_ttl(list[0])
+            name = curname
+        else:
+            return ret
+
+        rrtype = list[2]
+        rdata = ' '.join(list[3:])
+        ret = name, ttl, rrclass, rrtype, rdata
+    return ret
+
+#########################################################################
+# two: try parsing on the assumption that the RR type is specified in
+# field 2, and field 1 is either name or ttl
+# input:
+#   a record to parse, and the most recent name found in prior records
+# returns:
+#   empty list if parse failed, else name, ttl, class, type, rdata
+# throws:
+#   MasterFileError
+#########################################################################
+def two(record, curname):
+    global defttl, defclass
+    ret = ''
+    list = record.split()
+    if len(list) <= 2:
+        return ret
+
+    if istype(list[1]):
+        rrclass = defclass
+        rrtype = list[1]
+        if list[0].lower() == 'rrsig':
+            name = curname
+            ttl = defttl
+            rrtype = list[0]
+            rdata = ' '.join(list[1:])
+        elif isttl(list[0]):
+            ttl = parse_ttl(list[0])
+            name = curname
+            rdata = ' '.join(list[2:])
+        elif isname(list[0]):
+            name = list[0]
+            ttl = defttl
+            rdata = ' '.join(list[2:])
+        else:
+            raise MasterFileError("Cannot parse RR: " + record)
+
+        ret = name, ttl, rrclass, rrtype, rdata
+
+    return ret
+
+
+#########################################################################
+# reset: reset the state of the master file parser; use when parsing
+# more than one file
+#########################################################################
+def reset():
+    global defttl, origin
+    defttl = -1
+    origin=''
+
+#########################################################################
+# do_parse: parse a zone master file and return it as an array of
+# tuples
+#########################################################################
+def do_parse(file, initial_origin = '.'):
+    global defttl, origin, defclass
+
+    if not origin:
+        origin = initial_origin
+
+    zone = []
+    name = ''
+
+    data = open(file).read().splitlines()
+    for record in records(data):
+        if directive(record):
+            continue
+
+        incl = include(record)
+        if incl:
+            zone += incl
+            continue
+    
+        first = record.split()[0]
+        if first == '@':
+            name = origin
+            at, record = pop(record)
+
+        result = four(record, name)
+
+        if not result:
+            result = three(record, name)
+
+        if not result:
+            result = two(record, name)
+
+        if not result:
+            first, rdata = pop(record)
+            if istype(first):
+                result = name, defttl, defclass, first, rdata
+
+        if not result:
+            raise MasterFileError("Cannot parse RR: " + record)
+
+        name, ttl, rrclass, rrtype, rdata = result
+        if name[-1] != '.':
+            name += '.' + origin
+
+        if rrclass.upper() != 'IN':
+            raise MasterFileError("CH and HS zones not supported")
+
+        # add origin to rdata if necessary
+        if rrtype.lower() in ('cname', 'dname', 'ns'):
+            if not isname(rdata):
+                raise MasterFileError("Invalid " + rrtype + ": " + rdata)
+            if rdata[-1] != '.':
+                rdata += '.' + origin
+
+        if (ttl == -1):
+            raise MasterFileError("No TTL specified; zone rejected")
+
+        zone.append((name, ttl, rrclass, rrtype, rdata))
+
+    return zone
+
+#########################################################################
+# parse: call do_parse on behalf of a caller; determine the zone name
+# and return the zone data
+# input:
+#   filename
+# returns:
+#   zonename, data
+#########################################################################
+def parse(file, initial_origin = '.'):
+    zone = do_parse(file, initial_origin)
+    zonename = ''
+    for record in zone:
+        if record[3].lower() == 'soa':
+            zonename = record[0]
+    if not zonename:
+        raise MasterFileError("No SOA; zone rejected")
+    return zonename, zone
+
+#########################################################################
+# main: used for testing; parse a zone file and print out each record
+# broken up into separate name, ttl, class, type, and rdata files
+#########################################################################
+def main():
+    print ('---------------------')
+    try:
+        file = sys.argv[1]
+    except:
+        file = 'testfile'
+    zone = parse(file)
+    for name, ttl, rrclass, rrtype, rdata in zone:
+        print ('name: ' + name)
+        print ('ttl: ' + str(ttl))
+        print ('rrclass: ' + rrclass)
+        print ('rrtype: ' + rrtype)
+        print ('rdata: ' + rdata)
+        print ('---------------------')
+
+# initialize
+reset()
+
+if __name__ == "__main__":
+    main()

+ 158 - 0
src/lib/python/isc/auth/sqlite3_ds.py

@@ -0,0 +1,158 @@
+# Copyright (C) 2010  Internet Systems Consortium.
+#
+# 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 INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM 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.
+
+import sqlite3, re, random
+import isc
+
+#########################################################################
+# define exceptions
+#########################################################################
+class Sqlite3DSError(Exception):
+    pass
+
+#########################################################################
+# create: set up schema for a newly created zones/records database
+#########################################################################
+def create(cur):
+    """Create new zone database"""
+    cur.execute("CREATE TABLE schema_version (version INTEGER NOT NULL)")
+    cur.execute("INSERT INTO schema_version VALUES (1)")
+    cur.execute("""CREATE TABLE zones (id INTEGER PRIMARY KEY, 
+                   name STRING NOT NULL, rdclass STRING NOT NULL DEFAULT 'IN', 
+                   dnssec BOOLEAN NOT NULL DEFAULT 0)""")
+    cur.execute("CREATE INDEX zones_byname ON zones (name)")
+    cur.execute("""CREATE TABLE records (id INTEGER PRIMARY KEY, 
+                   zone_id INTEGER NOT NULL, name STRING NOT NULL,
+                   rname STRING NOT NULL, ttl INTEGER NOT NULL,
+                   rdtype STRING NOT NULL, sigtype STRING,
+                   rdata STRING NOT NULL)""")
+    cur.execute("CREATE INDEX records_byname ON records (name)")
+    cur.execute("CREATE INDEX records_byrname ON records (rname)")
+    cur.execute("""CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, 
+                   zone_id INTEGER NOT NULL, hash STRING NOT NULL,
+                   rhash STRING NOT NULL, owner STRING NOT NULL,
+                   rowner STRING NOT NULL, ttl INTEGER NOT NULL,
+                   rdtype STRING NOT NULL, rdata STRING NOT NULL)""")
+    cur.execute("CREATE INDEX nsec3_byhash ON nsec3 (hash)")
+    cur.execute("CREATE INDEX nsec3_byrhash ON nsec3 (rhash)")
+    cur.execute("CREATE INDEX nsec3_byowner ON nsec3 (owner)")
+    cur.execute("CREATE INDEX nsec3_byrowner ON nsec3 (rowner)")
+
+#########################################################################
+# open: open a database.  if the database is not yet set up, 
+# call create to do so.
+# input:
+#   dbfile - the filename for the sqlite3 database
+# returns:
+#   sqlite3 connection, sqlite3 cursor
+#########################################################################
+def open(dbfile):
+    """Open the database file.  If necessary, set it up"""
+    try: 
+        conn = sqlite3.connect(dbfile)
+        cur = conn.cursor()
+    except Exception as e:
+        fail = "Failed to open " + dbfile + ": " + e.args[0]
+        raise Sqlite3DSError(fail)
+
+    # Does the database exist yet?  If not, create it.
+    try:
+        cur.execute("SELECT version FROM schema_version")
+        row = cur.fetchone()
+    except:
+        create(cur)
+        conn.commit()
+        row = [1]
+
+    if row == None or row[0] != 1:
+        raise Sqlite3DSError("Bad database schema version")
+
+    return conn, cur
+
+#########################################################################
+# get_zoneid:
+#   returns the zone_id for a given zone name, or an empty
+#   string if the zone is not found
+#########################################################################
+def get_zoneid(zone, cur):
+    cur.execute("SELECT id FROM zones WHERE name = ?", [zone])
+    row = cur.fetchone()
+    if row:
+        return row[0]
+    else:
+        return ''
+
+#########################################################################
+# reverse_name:
+#   reverse the labels of a DNS name.  (for example,
+#   "bind10.isc.org." would become "org.isc.bind10.")
+#########################################################################
+def reverse_name(name):
+    """Reverse the labels of a domain name; for example,
+    given 'www.isc.org.', return 'org.isc.www.'  This is needed
+    for DNSSEC sort order."""
+    new = name.split('.')
+    new.reverse()
+    if new[0] == '':
+        new.pop(0)
+    return '.'.join(new)+'.'
+
+
+#########################################################################
+# load:
+#   load a zone into the SQL database.
+# input:
+#   dbfile: the sqlite3 database fileanme
+#   zone: the zone origin
+#   zonedata: an array of name/ttl/class/rrtype/rdata-text tuples
+#########################################################################
+def load(dbfile, zone, zonedata):
+    conn, cur = open(dbfile)
+    old_zone_id = get_zoneid(zone, cur)
+
+    temp = str(random.randrange(100000))
+    cur.execute("INSERT INTO zones (name, rdclass) VALUES (?, 'IN')", [temp])
+    new_zone_id = cur.lastrowid
+
+    for name, ttl, rdclass, rdtype, rdata in zonedata:
+        sigtype = ''
+        if rdtype.lower() == 'rrsig':
+            sigtype = rdata.split()[0]
+
+        if sigtype:
+            cur.execute("""INSERT INTO records
+                           (zone_id, name, rname, ttl, rdtype, sigtype, rdata)
+                           VALUES (?, ?, ?, ?, ?, ?, ?)""",
+                        [new_zone_id, name, reverse_name(name), ttl,
+                        rdtype, sigtype, rdata])
+        else:
+            cur.execute("""INSERT INTO records
+                           (zone_id, name, rname, ttl, rdtype, rdata)
+                           VALUES (?, ?, ?, ?, ?, ?)""",
+                        [new_zone_id, name, reverse_name(name), ttl,
+                        rdtype, rdata])
+
+    if old_zone_id:
+        cur.execute("DELETE FROM zones WHERE id=?", [old_zone_id])
+        cur.execute("UPDATE zones SET name=? WHERE id=?", [zone, new_zone_id])
+        conn.commit()
+        cur.execute("DELETE FROM records WHERE zone_id=?", [old_zone_id])
+        conn.commit()
+    else:
+        cur.execute("UPDATE zones SET name=? WHERE id=?", [zone, new_zone_id])
+        conn.commit()
+
+    cur.close()
+    conn.close()