From 387965661eaa775833b1e35b917f8e568ab7f5c6 Mon Sep 17 00:00:00 2001 From: dougb Date: Sat, 16 Jul 2011 10:49:33 +0000 Subject: Vendor import of BIND 9.8.0-P4 --- lib/bind9/Makefile.in | 4 +- lib/bind9/api | 4 +- lib/bind9/check.c | 549 +- lib/bind9/include/bind9/getaddresses.h | 2 +- lib/dns/Makefile.in | 44 +- lib/dns/acl.c | 2 +- lib/dns/adb.c | 581 +- lib/dns/api | 4 +- lib/dns/byaddr.c | 47 +- lib/dns/cache.c | 78 +- lib/dns/client.c | 3019 +++++ lib/dns/db.c | 46 +- lib/dns/diff.c | 19 +- lib/dns/dispatch.c | 93 +- lib/dns/dlz.c | 154 +- lib/dns/dns64.c | 299 + lib/dns/dnssec.c | 804 +- lib/dns/ds.c | 72 +- lib/dns/dst_api.c | 489 +- lib/dns/dst_internal.h | 40 +- lib/dns/dst_openssl.h | 9 +- lib/dns/dst_parse.c | 193 +- lib/dns/dst_parse.h | 21 +- lib/dns/ecdb.c | 810 ++ lib/dns/forward.c | 22 +- lib/dns/gen-unix.h | 2 +- lib/dns/gen.c | 6 +- lib/dns/gssapi_link.c | 91 +- lib/dns/gssapictx.c | 96 +- lib/dns/hmac_link.c | 211 +- lib/dns/include/dns/Makefile.in | 20 +- lib/dns/include/dns/acl.h | 2 +- lib/dns/include/dns/cache.h | 39 +- lib/dns/include/dns/client.h | 621 + lib/dns/include/dns/compress.h | 2 +- lib/dns/include/dns/db.h | 49 +- lib/dns/include/dns/diff.h | 2 +- lib/dns/include/dns/dispatch.h | 2 +- lib/dns/include/dns/dlz.h | 62 +- lib/dns/include/dns/dns64.h | 175 + lib/dns/include/dns/dnssec.h | 137 +- lib/dns/include/dns/ds.h | 9 +- lib/dns/include/dns/ecdb.h | 52 + lib/dns/include/dns/events.h | 7 +- lib/dns/include/dns/forward.h | 19 +- lib/dns/include/dns/journal.h | 2 +- lib/dns/include/dns/keydata.h | 55 + lib/dns/include/dns/keytable.h | 212 +- lib/dns/include/dns/keyvalues.h | 8 +- lib/dns/include/dns/lib.h | 18 +- lib/dns/include/dns/log.h | 3 +- lib/dns/include/dns/lookup.h | 2 +- lib/dns/include/dns/master.h | 5 +- lib/dns/include/dns/masterdump.h | 2 +- lib/dns/include/dns/message.h | 20 +- lib/dns/include/dns/name.h | 84 +- lib/dns/include/dns/ncache.h | 2 +- lib/dns/include/dns/nsec3.h | 61 +- lib/dns/include/dns/peer.h | 2 +- lib/dns/include/dns/private.h | 55 + lib/dns/include/dns/rbt.h | 19 +- lib/dns/include/dns/rdata.h | 55 +- lib/dns/include/dns/rdataset.h | 2 +- lib/dns/include/dns/request.h | 11 +- lib/dns/include/dns/resolver.h | 28 +- lib/dns/include/dns/result.h | 9 +- lib/dns/include/dns/rpz.h | 189 + lib/dns/include/dns/rriterator.h | 103 + lib/dns/include/dns/sdb.h | 2 +- lib/dns/include/dns/sdlz.h | 130 +- lib/dns/include/dns/secalg.h | 11 +- lib/dns/include/dns/soa.h | 26 +- lib/dns/include/dns/ssu.h | 31 +- lib/dns/include/dns/stats.h | 2 +- lib/dns/include/dns/tkey.h | 14 +- lib/dns/include/dns/tsec.h | 135 + lib/dns/include/dns/tsig.h | 32 +- lib/dns/include/dns/types.h | 18 +- lib/dns/include/dns/validator.h | 2 +- lib/dns/include/dns/view.h | 211 +- lib/dns/include/dns/xfrin.h | 2 +- lib/dns/include/dns/zone.h | 109 +- lib/dns/include/dst/dst.h | 241 +- lib/dns/include/dst/gssapi.h | 13 +- lib/dns/iptable.c | 2 +- lib/dns/journal.c | 8 +- lib/dns/keydata.c | 89 + lib/dns/keytable.c | 389 +- lib/dns/lib.c | 109 +- lib/dns/log.c | 5 +- lib/dns/master.c | 113 +- lib/dns/masterdump.c | 65 +- lib/dns/message.c | 59 +- lib/dns/name.c | 77 +- lib/dns/ncache.c | 57 +- lib/dns/nsec.c | 2 +- lib/dns/nsec3.c | 490 +- lib/dns/openssl_link.c | 231 +- lib/dns/openssldh_link.c | 45 +- lib/dns/openssldsa_link.c | 47 +- lib/dns/opensslgost_link.c | 418 + lib/dns/opensslrsa_link.c | 166 +- lib/dns/peer.c | 6 +- lib/dns/private.c | 295 + lib/dns/rbt.c | 9 +- lib/dns/rbtdb.c | 826 +- lib/dns/rcode.c | 27 +- lib/dns/rdata.c | 143 +- lib/dns/rdata/any_255/tsig_250.c | 9 +- lib/dns/rdata/ch_3/a_1.c | 12 +- lib/dns/rdata/generic/afsdb_18.c | 8 +- lib/dns/rdata/generic/cert_37.c | 10 +- lib/dns/rdata/generic/cname_5.c | 9 +- lib/dns/rdata/generic/dlv_32769.c | 36 +- lib/dns/rdata/generic/dname_39.c | 8 +- lib/dns/rdata/generic/dnskey_48.c | 41 +- lib/dns/rdata/generic/ds_43.c | 32 +- lib/dns/rdata/generic/gpos_27.c | 9 +- lib/dns/rdata/generic/hinfo_13.c | 8 +- lib/dns/rdata/generic/hip_55.c | 506 + lib/dns/rdata/generic/hip_55.h | 47 + lib/dns/rdata/generic/ipseckey_45.c | 41 +- lib/dns/rdata/generic/isdn_20.c | 9 +- lib/dns/rdata/generic/key_25.c | 37 +- lib/dns/rdata/generic/keydata_65533.c | 377 + lib/dns/rdata/generic/keydata_65533.h | 35 + lib/dns/rdata/generic/loc_29.c | 7 +- lib/dns/rdata/generic/mb_7.c | 15 +- lib/dns/rdata/generic/md_3.c | 15 +- lib/dns/rdata/generic/mf_4.c | 15 +- lib/dns/rdata/generic/mg_8.c | 15 +- lib/dns/rdata/generic/minfo_14.c | 21 +- lib/dns/rdata/generic/mr_9.c | 15 +- lib/dns/rdata/generic/mx_15.c | 13 +- lib/dns/rdata/generic/ns_2.c | 15 +- lib/dns/rdata/generic/nsec3_50.c | 7 +- lib/dns/rdata/generic/nsec3param_51.c | 7 +- lib/dns/rdata/generic/nsec_47.c | 36 +- lib/dns/rdata/generic/null_10.c | 9 +- lib/dns/rdata/generic/nxt_30.c | 8 +- lib/dns/rdata/generic/opt_41.c | 9 +- lib/dns/rdata/generic/proforma.c | 21 +- lib/dns/rdata/generic/ptr_12.c | 14 +- lib/dns/rdata/generic/rp_17.c | 20 +- lib/dns/rdata/generic/rrsig_46.c | 47 +- lib/dns/rdata/generic/rt_21.c | 13 +- lib/dns/rdata/generic/sig_24.c | 8 +- lib/dns/rdata/generic/soa_6.c | 7 +- lib/dns/rdata/generic/spf_99.c | 8 +- lib/dns/rdata/generic/sshfp_44.c | 9 +- lib/dns/rdata/generic/tkey_249.c | 8 +- lib/dns/rdata/generic/txt_16.c | 9 +- lib/dns/rdata/generic/unspec_103.c | 9 +- lib/dns/rdata/generic/x25_19.c | 9 +- lib/dns/rdata/hs_4/a_1.c | 9 +- lib/dns/rdata/in_1/a6_38.c | 9 +- lib/dns/rdata/in_1/a_1.c | 9 +- lib/dns/rdata/in_1/aaaa_28.c | 8 +- lib/dns/rdata/in_1/apl_42.c | 9 +- lib/dns/rdata/in_1/dhcid_49.c | 11 +- lib/dns/rdata/in_1/kx_36.c | 13 +- lib/dns/rdata/in_1/naptr_35.c | 136 +- lib/dns/rdata/in_1/nsap-ptr_23.c | 15 +- lib/dns/rdata/in_1/nsap_22.c | 9 +- lib/dns/rdata/in_1/px_26.c | 13 +- lib/dns/rdata/in_1/srv_33.c | 13 +- lib/dns/rdata/in_1/wks_11.c | 7 +- lib/dns/rdatalist.c | 2 +- lib/dns/rdataset.c | 2 +- lib/dns/rdataslab.c | 28 +- lib/dns/request.c | 10 +- lib/dns/resolver.c | 630 +- lib/dns/result.c | 7 +- lib/dns/rootns.c | 2 +- lib/dns/rpz.c | 1168 ++ lib/dns/rriterator.c | 202 + lib/dns/sdb.c | 8 +- lib/dns/sdlz.c | 413 +- lib/dns/soa.c | 40 +- lib/dns/spnego.c | 9 +- lib/dns/ssu.c | 68 +- lib/dns/ssu_external.c | 265 + lib/dns/stats.c | 2 +- lib/dns/time.c | 2 +- lib/dns/tkey.c | 53 +- lib/dns/tsec.c | 160 + lib/dns/tsig.c | 367 +- lib/dns/validator.c | 428 +- lib/dns/view.c | 421 +- lib/dns/xfrin.c | 43 +- lib/dns/zone.c | 13033 +++++++++++++-------- lib/export/Makefile.in | 27 + lib/export/dns/Makefile.in | 179 + lib/export/dns/include/Makefile.in | 23 + lib/export/dns/include/dns/Makefile.in | 56 + lib/export/dns/include/dst/Makefile.in | 36 + lib/export/irs/Makefile.in | 86 + lib/export/irs/include/Makefile.in | 24 + lib/export/irs/include/irs/Makefile.in | 46 + lib/export/isc/Makefile.in | 139 + lib/export/isc/include/Makefile.in | 24 + lib/export/isc/include/isc/Makefile.in | 66 + lib/export/isc/include/isc/bind9.h | 30 + lib/export/isc/nls/Makefile.in | 35 + lib/export/isc/nothreads/Makefile.in | 40 + lib/export/isc/nothreads/include/Makefile.in | 24 + lib/export/isc/nothreads/include/isc/Makefile.in | 36 + lib/export/isc/pthreads/Makefile.in | 38 + lib/export/isc/pthreads/include/Makefile.in | 24 + lib/export/isc/pthreads/include/isc/Makefile.in | 36 + lib/export/isc/unix/Makefile.in | 57 + lib/export/isc/unix/include/Makefile.in | 24 + lib/export/isc/unix/include/isc/Makefile.in | 37 + lib/export/isccfg/Makefile.in | 83 + lib/export/isccfg/include/Makefile.in | 24 + lib/export/isccfg/include/isccfg/Makefile.in | 42 + lib/export/samples/Makefile-postinstall.in | 78 + lib/export/samples/Makefile.in | 98 + lib/export/samples/nsprobe.c | 1220 ++ lib/export/samples/sample-async.c | 402 + lib/export/samples/sample-gai.c | 77 + lib/export/samples/sample-request.c | 263 + lib/export/samples/sample-update.c | 755 ++ lib/export/samples/sample.c | 378 + lib/irs/Makefile.in | 80 + lib/irs/api | 3 + lib/irs/context.c | 396 + lib/irs/dnsconf.c | 269 + lib/irs/gai_strerror.c | 93 + lib/irs/getaddrinfo.c | 1295 ++ lib/irs/getnameinfo.c | 410 + lib/irs/include/Makefile.in | 24 + lib/irs/include/irs/Makefile.in | 44 + lib/irs/include/irs/context.h | 159 + lib/irs/include/irs/dnsconf.h | 94 + lib/irs/include/irs/netdb.h.in | 167 + lib/irs/include/irs/platform.h.in | 45 + lib/irs/include/irs/resconf.h | 113 + lib/irs/include/irs/types.h | 31 + lib/irs/include/irs/version.h | 27 + lib/irs/resconf.c | 636 + lib/irs/version.c | 27 + lib/isc/Makefile.in | 38 +- lib/isc/alpha/include/isc/atomic.h | 2 +- lib/isc/api | 6 +- lib/isc/app_api.c | 136 + lib/isc/assertions.c | 64 +- lib/isc/backtrace-emptytbl.c | 34 + lib/isc/backtrace.c | 285 + lib/isc/base32.c | 2 +- lib/isc/base64.c | 2 +- lib/isc/entropy.c | 2 +- lib/isc/hash.c | 20 +- lib/isc/heap.c | 2 +- lib/isc/hmacmd5.c | 35 +- lib/isc/hmacsha.c | 269 +- lib/isc/httpd.c | 2 +- lib/isc/ia64/include/isc/atomic.h | 2 +- lib/isc/include/isc/Makefile.in | 10 +- lib/isc/include/isc/app.h | 173 +- lib/isc/include/isc/assertions.h | 8 +- lib/isc/include/isc/backtrace.h | 131 + lib/isc/include/isc/bind9.h | 30 + lib/isc/include/isc/buffer.h | 4 +- lib/isc/include/isc/entropy.h | 2 +- lib/isc/include/isc/error.h | 9 +- lib/isc/include/isc/file.h | 31 +- lib/isc/include/isc/fsaccess.h | 2 +- lib/isc/include/isc/hash.h | 2 +- lib/isc/include/isc/heap.h | 2 +- lib/isc/include/isc/hmacmd5.h | 13 +- lib/isc/include/isc/hmacsha.h | 17 +- lib/isc/include/isc/lib.h | 13 +- lib/isc/include/isc/log.h | 2 +- lib/isc/include/isc/md5.h | 14 +- lib/isc/include/isc/mem.h | 161 +- lib/isc/include/isc/msgs.h | 6 +- lib/isc/include/isc/namespace.h | 164 + lib/isc/include/isc/netaddr.h | 2 +- lib/isc/include/isc/netscope.h | 2 +- lib/isc/include/isc/platform.h.in | 24 +- lib/isc/include/isc/portset.h | 2 +- lib/isc/include/isc/radix.h | 2 +- lib/isc/include/isc/random.h | 2 +- lib/isc/include/isc/ratelimiter.h | 2 +- lib/isc/include/isc/refcount.h | 12 +- lib/isc/include/isc/result.h | 5 +- lib/isc/include/isc/resultclass.h | 5 +- lib/isc/include/isc/serial.h | 2 +- lib/isc/include/isc/sha1.h | 13 +- lib/isc/include/isc/sha2.h | 17 +- lib/isc/include/isc/sockaddr.h | 2 +- lib/isc/include/isc/socket.h | 149 +- lib/isc/include/isc/stats.h | 2 +- lib/isc/include/isc/symtab.h | 2 +- lib/isc/include/isc/task.h | 108 +- lib/isc/include/isc/timer.h | 93 +- lib/isc/include/isc/types.h | 9 +- lib/isc/include/isc/util.h | 2 +- lib/isc/inet_aton.c | 4 +- lib/isc/inet_ntop.c | 2 +- lib/isc/iterated_hash.c | 2 +- lib/isc/lib.c | 34 +- lib/isc/log.c | 2 +- lib/isc/md5.c | 30 +- lib/isc/mem.c | 573 +- lib/isc/mem_api.c | 303 + lib/isc/netaddr.c | 24 +- lib/isc/nls/Makefile.in | 4 +- lib/isc/nothreads/Makefile.in | 8 +- lib/isc/powerpc/include/isc/atomic.h | 2 +- lib/isc/print.c | 2 +- lib/isc/pthreads/Makefile.in | 4 +- lib/isc/pthreads/mutex.c | 2 +- lib/isc/radix.c | 2 +- lib/isc/random.c | 4 +- lib/isc/rwlock.c | 2 +- lib/isc/sha1.c | 41 +- lib/isc/sha2.c | 429 +- lib/isc/sockaddr.c | 8 +- lib/isc/socket_api.c | 216 + lib/isc/stats.c | 2 +- lib/isc/task.c | 517 +- lib/isc/task_api.c | 216 + lib/isc/task_p.h | 8 +- lib/isc/timer.c | 346 +- lib/isc/timer_api.c | 144 + lib/isc/timer_p.h | 8 +- lib/isc/unix/Makefile.in | 4 +- lib/isc/unix/app.c | 540 +- lib/isc/unix/dir.c | 4 +- lib/isc/unix/entropy.c | 4 +- lib/isc/unix/file.c | 90 +- lib/isc/unix/ifiter_getifaddrs.c | 2 +- lib/isc/unix/ifiter_ioctl.c | 2 +- lib/isc/unix/include/isc/net.h | 4 +- lib/isc/unix/include/isc/offset.h | 4 +- lib/isc/unix/include/isc/strerror.h | 4 +- lib/isc/unix/include/isc/time.h | 2 +- lib/isc/unix/interfaceiter.c | 4 +- lib/isc/unix/resource.c | 2 +- lib/isc/unix/socket.c | 952 +- lib/isc/unix/socket_p.h | 9 +- lib/isc/unix/strerror.c | 2 +- lib/isccc/Makefile.in | 6 +- lib/isccc/api | 4 +- lib/isccfg/Makefile.in | 8 +- lib/isccfg/aclconf.c | 25 +- lib/isccfg/api | 6 +- lib/isccfg/dnsconf.c | 69 + lib/isccfg/include/isccfg/aclconf.h | 14 +- lib/isccfg/include/isccfg/cfg.h | 38 +- lib/isccfg/include/isccfg/dnsconf.h | 35 + lib/isccfg/include/isccfg/grammar.h | 24 +- lib/isccfg/include/isccfg/log.h | 2 +- lib/isccfg/include/isccfg/namedconf.h | 16 +- lib/isccfg/namedconf.c | 588 +- lib/isccfg/parser.c | 92 +- lib/lwres/api | 4 +- lib/lwres/context.c | 2 +- lib/lwres/context_p.h | 2 +- lib/lwres/getaddrinfo.c | 4 +- lib/lwres/getipnode.c | 2 +- lib/lwres/include/lwres/context.h | 2 +- lib/lwres/include/lwres/netdb.h.in | 2 +- lib/lwres/lwconfig.c | 2 +- lib/lwres/man/lwres.3 | 2 +- lib/lwres/man/lwres.html | 14 +- lib/lwres/man/lwres_buffer.3 | 2 +- lib/lwres/man/lwres_buffer.html | 6 +- lib/lwres/man/lwres_config.3 | 2 +- lib/lwres/man/lwres_config.html | 12 +- lib/lwres/man/lwres_context.3 | 2 +- lib/lwres/man/lwres_context.html | 10 +- lib/lwres/man/lwres_gabn.3 | 2 +- lib/lwres/man/lwres_gabn.html | 10 +- lib/lwres/man/lwres_gai_strerror.3 | 2 +- lib/lwres/man/lwres_gai_strerror.html | 8 +- lib/lwres/man/lwres_getaddrinfo.3 | 2 +- lib/lwres/man/lwres_getaddrinfo.html | 10 +- lib/lwres/man/lwres_gethostent.3 | 2 +- lib/lwres/man/lwres_gethostent.html | 12 +- lib/lwres/man/lwres_getipnode.3 | 2 +- lib/lwres/man/lwres_getipnode.html | 10 +- lib/lwres/man/lwres_getnameinfo.3 | 2 +- lib/lwres/man/lwres_getnameinfo.html | 12 +- lib/lwres/man/lwres_getrrsetbyname.3 | 2 +- lib/lwres/man/lwres_getrrsetbyname.html | 10 +- lib/lwres/man/lwres_gnba.3 | 2 +- lib/lwres/man/lwres_gnba.html | 10 +- lib/lwres/man/lwres_hstrerror.3 | 2 +- lib/lwres/man/lwres_hstrerror.html | 10 +- lib/lwres/man/lwres_inetntop.3 | 2 +- lib/lwres/man/lwres_inetntop.html | 10 +- lib/lwres/man/lwres_noop.3 | 2 +- lib/lwres/man/lwres_noop.html | 10 +- lib/lwres/man/lwres_packet.3 | 2 +- lib/lwres/man/lwres_packet.html | 8 +- lib/lwres/man/lwres_resutil.3 | 2 +- lib/lwres/man/lwres_resutil.html | 10 +- lib/lwres/print_p.h | 2 +- 401 files changed, 41538 insertions(+), 8617 deletions(-) create mode 100644 lib/dns/client.c create mode 100644 lib/dns/dns64.c create mode 100644 lib/dns/ecdb.c create mode 100644 lib/dns/include/dns/client.h create mode 100644 lib/dns/include/dns/dns64.h create mode 100644 lib/dns/include/dns/ecdb.h create mode 100644 lib/dns/include/dns/keydata.h create mode 100644 lib/dns/include/dns/private.h create mode 100644 lib/dns/include/dns/rpz.h create mode 100644 lib/dns/include/dns/rriterator.h create mode 100644 lib/dns/include/dns/tsec.h create mode 100644 lib/dns/keydata.c create mode 100644 lib/dns/opensslgost_link.c create mode 100644 lib/dns/private.c create mode 100644 lib/dns/rdata/generic/hip_55.c create mode 100644 lib/dns/rdata/generic/hip_55.h create mode 100644 lib/dns/rdata/generic/keydata_65533.c create mode 100644 lib/dns/rdata/generic/keydata_65533.h create mode 100644 lib/dns/rpz.c create mode 100644 lib/dns/rriterator.c create mode 100644 lib/dns/ssu_external.c create mode 100644 lib/dns/tsec.c create mode 100644 lib/export/Makefile.in create mode 100644 lib/export/dns/Makefile.in create mode 100644 lib/export/dns/include/Makefile.in create mode 100644 lib/export/dns/include/dns/Makefile.in create mode 100644 lib/export/dns/include/dst/Makefile.in create mode 100644 lib/export/irs/Makefile.in create mode 100644 lib/export/irs/include/Makefile.in create mode 100644 lib/export/irs/include/irs/Makefile.in create mode 100644 lib/export/isc/Makefile.in create mode 100644 lib/export/isc/include/Makefile.in create mode 100644 lib/export/isc/include/isc/Makefile.in create mode 100644 lib/export/isc/include/isc/bind9.h create mode 100644 lib/export/isc/nls/Makefile.in create mode 100644 lib/export/isc/nothreads/Makefile.in create mode 100644 lib/export/isc/nothreads/include/Makefile.in create mode 100644 lib/export/isc/nothreads/include/isc/Makefile.in create mode 100644 lib/export/isc/pthreads/Makefile.in create mode 100644 lib/export/isc/pthreads/include/Makefile.in create mode 100644 lib/export/isc/pthreads/include/isc/Makefile.in create mode 100644 lib/export/isc/unix/Makefile.in create mode 100644 lib/export/isc/unix/include/Makefile.in create mode 100644 lib/export/isc/unix/include/isc/Makefile.in create mode 100644 lib/export/isccfg/Makefile.in create mode 100644 lib/export/isccfg/include/Makefile.in create mode 100644 lib/export/isccfg/include/isccfg/Makefile.in create mode 100644 lib/export/samples/Makefile-postinstall.in create mode 100644 lib/export/samples/Makefile.in create mode 100644 lib/export/samples/nsprobe.c create mode 100644 lib/export/samples/sample-async.c create mode 100644 lib/export/samples/sample-gai.c create mode 100644 lib/export/samples/sample-request.c create mode 100644 lib/export/samples/sample-update.c create mode 100644 lib/export/samples/sample.c create mode 100644 lib/irs/Makefile.in create mode 100644 lib/irs/api create mode 100644 lib/irs/context.c create mode 100644 lib/irs/dnsconf.c create mode 100644 lib/irs/gai_strerror.c create mode 100644 lib/irs/getaddrinfo.c create mode 100644 lib/irs/getnameinfo.c create mode 100644 lib/irs/include/Makefile.in create mode 100644 lib/irs/include/irs/Makefile.in create mode 100644 lib/irs/include/irs/context.h create mode 100644 lib/irs/include/irs/dnsconf.h create mode 100644 lib/irs/include/irs/netdb.h.in create mode 100644 lib/irs/include/irs/platform.h.in create mode 100644 lib/irs/include/irs/resconf.h create mode 100644 lib/irs/include/irs/types.h create mode 100644 lib/irs/include/irs/version.h create mode 100644 lib/irs/resconf.c create mode 100644 lib/irs/version.c create mode 100644 lib/isc/app_api.c create mode 100644 lib/isc/backtrace-emptytbl.c create mode 100644 lib/isc/backtrace.c create mode 100644 lib/isc/include/isc/backtrace.h create mode 100644 lib/isc/include/isc/bind9.h create mode 100644 lib/isc/include/isc/namespace.h create mode 100644 lib/isc/mem_api.c create mode 100644 lib/isc/socket_api.c create mode 100644 lib/isc/task_api.c create mode 100644 lib/isc/timer_api.c create mode 100644 lib/isccfg/dnsconf.c create mode 100644 lib/isccfg/include/isccfg/dnsconf.h (limited to 'lib') diff --git a/lib/bind9/Makefile.in b/lib/bind9/Makefile.in index e37d524..ffc2ad9 100644 --- a/lib/bind9/Makefile.in +++ b/lib/bind9/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 2001 Internet Software Consortium. # # Permission to use, copy, modify, and/or distribute this software for any @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.11 2007-06-19 23:47:16 tbox Exp $ +# $Id: Makefile.in,v 1.14 2009-12-05 23:31:40 each Exp $ srcdir = @srcdir@ VPATH = @srcdir@ diff --git a/lib/bind9/api b/lib/bind9/api index f3b0f9f..78dd0b4 100644 --- a/lib/bind9/api +++ b/lib/bind9/api @@ -1,3 +1,3 @@ -LIBINTERFACE = 50 -LIBREVISION = 4 +LIBINTERFACE = 80 +LIBREVISION = 1 LIBAGE = 0 diff --git a/lib/bind9/check.c b/lib/bind9/check.c index 76ca510..6fa9aa9 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2001-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: check.c,v 1.95.12.6 2010-03-04 23:47:53 tbox Exp $ */ +/* $Id: check.c,v 1.125 2011-01-07 23:47:07 tbox Exp $ */ /*! \file */ @@ -103,7 +103,7 @@ check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) { isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b, - dns_rootname, ISC_FALSE, NULL); + dns_rootname, 0, NULL); if (tresult != ISC_R_SUCCESS) { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "rrset-order: invalid name '%s'", str); @@ -202,7 +202,7 @@ check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) { dns_fixedname_init(&fixed); name = dns_fixedname_name(&fixed); tresult = dns_name_fromtext(name, &buffer, dns_rootname, - ISC_FALSE, NULL); + 0, NULL); if (tresult != ISC_R_SUCCESS) { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "bad name '%s'", str); @@ -265,7 +265,7 @@ disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) { str = cfg_obj_asstring(obj); isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); - tresult = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL); + tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); if (tresult != ISC_R_SUCCESS) { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "bad domain name '%s'", str); @@ -352,7 +352,7 @@ mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx, str = cfg_obj_asstring(obj); isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); - result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL); + result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "bad domain name '%s'", str); @@ -407,7 +407,7 @@ check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, static const char *acls[] = { "allow-query", "allow-query-on", "allow-query-cache", "allow-query-cache-on", "blackhole", "match-clients", "match-destinations", - "sortlist", NULL }; + "sortlist", "filter-aaaa", NULL }; while (acls[i] != NULL) { tresult = checkacl(acls[i++], actx, NULL, voptions, config, @@ -418,6 +418,106 @@ check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, return (result); } +static const unsigned char zeros[16]; + +static isc_result_t +check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, + const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) +{ + isc_result_t result = ISC_R_SUCCESS; + const cfg_obj_t *dns64 = NULL; + const cfg_obj_t *options; + const cfg_listelt_t *element; + const cfg_obj_t *map, *obj; + isc_netaddr_t na, sa; + unsigned int prefixlen; + int nbytes; + int i; + + static const char *acls[] = { "client", "exclude", "mapped", NULL}; + + if (voptions != NULL) + cfg_map_get(voptions, "dns64", &dns64); + if (config != NULL && dns64 == NULL) { + options = NULL; + cfg_map_get(config, "options", &options); + if (options != NULL) + cfg_map_get(options, "dns64", &dns64); + } + if (dns64 == NULL) + return (ISC_R_SUCCESS); + + for (element = cfg_list_first(dns64); + element != NULL; + element = cfg_list_next(element)) + { + map = cfg_listelt_value(element); + obj = cfg_map_getname(map); + + cfg_obj_asnetprefix(obj, &na, &prefixlen); + if (na.family != AF_INET6) { + cfg_obj_log(map, logctx, ISC_LOG_ERROR, + "dns64 requires a IPv6 prefix"); + result = ISC_R_FAILURE; + continue; + } + + if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 && + prefixlen != 56 && prefixlen != 64 && prefixlen != 96) { + cfg_obj_log(map, logctx, ISC_LOG_ERROR, + "bad prefix length %u [32/40/48/56/64/96]", + prefixlen); + result = ISC_R_FAILURE; + continue; + } + + for (i = 0; acls[i] != NULL; i++) { + obj = NULL; + (void)cfg_map_get(map, acls[i], &obj); + if (obj != NULL) { + dns_acl_t *acl = NULL; + isc_result_t tresult; + + tresult = cfg_acl_fromconfig(obj, config, + logctx, actx, + mctx, 0, &acl); + if (acl != NULL) + dns_acl_detach(&acl); + if (tresult != ISC_R_SUCCESS) + result = tresult; + } + } + + obj = NULL; + (void)cfg_map_get(map, "suffix", &obj); + if (obj != NULL) { + isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj)); + if (sa.family != AF_INET6) { + cfg_obj_log(map, logctx, ISC_LOG_ERROR, + "dns64 requires a IPv6 suffix"); + result = ISC_R_FAILURE; + continue; + } + nbytes = prefixlen / 8 + 4; + if (prefixlen >= 32 && prefixlen <= 64) + nbytes++; + if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) { + char netaddrbuf[ISC_NETADDR_FORMATSIZE]; + isc_netaddr_format(&sa, netaddrbuf, + sizeof(netaddrbuf)); + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "bad suffix '%s' leading " + "%u octets not zeros", + netaddrbuf, nbytes); + result = ISC_R_FAILURE; + } + } + } + + return (result); +} + + /* * Check allow-recursion and allow-recursion-on acls, and also log a * warning if they're inconsistent with the "recursion" option. @@ -493,6 +593,78 @@ check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, return (result); } +static isc_result_t +check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, + const char *viewname, const cfg_obj_t *config, + isc_log_t *logctx, isc_mem_t *mctx) +{ + const cfg_obj_t *options, *aclobj, *obj = NULL; + dns_acl_t *acl = NULL; + isc_result_t result = ISC_R_SUCCESS, tresult; + dns_v4_aaaa_t filter; + const char *forview = " for view "; + + if (voptions != NULL) + cfg_map_get(voptions, "filter-aaaa-on-v4", &obj); + if (obj == NULL && config != NULL) { + options = NULL; + cfg_map_get(config, "options", &options); + if (options != NULL) + cfg_map_get(options, "filter-aaaa-on-v4", &obj); + } + + if (obj == NULL) + filter = dns_v4_aaaa_ok; /* default */ + else if (cfg_obj_isboolean(obj)) + filter = cfg_obj_asboolean(obj) ? dns_v4_aaaa_filter : + dns_v4_aaaa_ok; + else + filter = dns_v4_aaaa_break_dnssec; /* break-dnssec */ + + if (viewname == NULL) { + viewname = ""; + forview = ""; + } + + aclobj = options = NULL; + acl = NULL; + + if (voptions != NULL) + cfg_map_get(voptions, "filter-aaaa", &aclobj); + if (config != NULL && aclobj == NULL) { + options = NULL; + cfg_map_get(config, "options", &options); + if (options != NULL) + cfg_map_get(options, "filter-aaaa", &aclobj); + } + if (aclobj == NULL) + return (result); + + tresult = cfg_acl_fromconfig(aclobj, config, logctx, + actx, mctx, 0, &acl); + + if (tresult != ISC_R_SUCCESS) { + result = tresult; + } else if (filter != dns_v4_aaaa_ok && dns_acl_isnone(acl)) { + cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING, + "both \"filter-aaaa-on-v4 %s;\" and " + "\"filter-aaaa\" is 'none;'%s%s", + filter == dns_v4_aaaa_break_dnssec ? + "break-dnssec" : "yes", forview, viewname); + result = ISC_R_FAILURE; + } else if (filter == dns_v4_aaaa_ok && !dns_acl_isnone(acl)) { + cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING, + "both \"filter-aaaa-on-v4 no;\" and " + "\"filter-aaaa\" is set%s%s", forview, viewname); + result = ISC_R_FAILURE; + } + + if (acl != NULL) + dns_acl_detach(&acl); + + return (result); +} + typedef struct { const char *name; unsigned int scale; @@ -524,6 +696,12 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) { { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */ }; + static const char *server_contact[] = { + "empty-server", "empty-contact", + "dns64-server", "dns64-contact", + NULL + }; + /* * Check that fields specified in units of time other than seconds * have reasonable values. @@ -620,7 +798,7 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) { isc_buffer_add(&b, strlen(str)); tresult = dns_name_fromtext(name, &b, dns_rootname, - ISC_FALSE, NULL); + 0, NULL); if (tresult != ISC_R_SUCCESS) { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "bad domain name '%s'", @@ -666,14 +844,24 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) { element = cfg_list_next(element)) { const char *dlv; + const cfg_obj_t *anchor; obj = cfg_listelt_value(element); dlv = cfg_obj_asstring(cfg_tuple_get(obj, "domain")); + anchor = cfg_tuple_get(obj, "trust-anchor"); + + /* + * If domain is "auto" and trust anchor is missing, + * skip remaining tests + */ + if (!strcmp(dlv, "auto") && cfg_obj_isvoid(anchor)) + continue; + isc_buffer_init(&b, dlv, strlen(dlv)); isc_buffer_add(&b, strlen(dlv)); tresult = dns_name_fromtext(name, &b, dns_rootname, - ISC_TRUE, NULL); + 0, NULL); if (tresult != ISC_R_SUCCESS) { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "bad domain name '%s'", dlv); @@ -701,19 +889,32 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) { if (result == ISC_R_SUCCESS) result = ISC_R_FAILURE; } - dlv = cfg_obj_asstring(cfg_tuple_get(obj, - "trust-anchor")); - isc_buffer_init(&b, dlv, strlen(dlv)); - isc_buffer_add(&b, strlen(dlv)); - tresult = dns_name_fromtext(name, &b, dns_rootname, - ISC_TRUE, NULL); - if (tresult != ISC_R_SUCCESS) { + + if (!cfg_obj_isvoid(anchor)) { + dlv = cfg_obj_asstring(anchor); + isc_buffer_init(&b, dlv, strlen(dlv)); + isc_buffer_add(&b, strlen(dlv)); + tresult = dns_name_fromtext(name, &b, + dns_rootname, + DNS_NAME_DOWNCASE, + NULL); + if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "bad domain name '%s'", + dlv); + if (result == ISC_R_SUCCESS) + result = tresult; + } + } else { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, - "bad domain name '%s'", dlv); + "dnssec-lookaside requires " + "either 'auto' or a domain and " + "trust anchor"); if (result == ISC_R_SUCCESS) - result = tresult; + result = ISC_R_FAILURE; } } + if (symtab != NULL) isc_symtab_destroy(&symtab); } @@ -743,38 +944,29 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) { } /* - * Check empty zone configuration. + * Check server/contacts for syntactic validity. */ - obj = NULL; - (void)cfg_map_get(options, "empty-server", &obj); - if (obj != NULL) { - str = cfg_obj_asstring(obj); - isc_buffer_init(&b, str, strlen(str)); - isc_buffer_add(&b, strlen(str)); - tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b, - dns_rootname, ISC_FALSE, NULL); - if (tresult != ISC_R_SUCCESS) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, - "empty-server: invalid name '%s'", str); - result = ISC_R_FAILURE; - } - } - - obj = NULL; - (void)cfg_map_get(options, "empty-contact", &obj); - if (obj != NULL) { - str = cfg_obj_asstring(obj); - isc_buffer_init(&b, str, strlen(str)); - isc_buffer_add(&b, strlen(str)); - tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b, - dns_rootname, ISC_FALSE, NULL); - if (tresult != ISC_R_SUCCESS) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, - "empty-contact: invalid name '%s'", str); - result = ISC_R_FAILURE; + for (i= 0; server_contact[i] != NULL; i++) { + obj = NULL; + (void)cfg_map_get(options, server_contact[i], &obj); + if (obj != NULL) { + str = cfg_obj_asstring(obj); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + tresult = dns_name_fromtext(dns_fixedname_name(&fixed), + &b, dns_rootname, 0, NULL); + if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "%s: invalid name '%s'", + server_contact[i], str); + result = ISC_R_FAILURE; + } } } + /* + * Check empty zone configuration. + */ obj = NULL; (void)cfg_map_get(options, "disable-empty-zone", &obj); for (element = cfg_list_first(obj); @@ -786,7 +978,7 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) { isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b, - dns_rootname, ISC_FALSE, NULL); + dns_rootname, 0, NULL); if (tresult != ISC_R_SUCCESS) { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "disable-empty-zone: invalid name '%s'", @@ -950,6 +1142,12 @@ check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) { const char *str; isc_buffer_t b; + /* Check for "update-policy local;" */ + if (cfg_obj_isstring(policy) && + strcmp("local", cfg_obj_asstring(policy)) == 0) + return (ISC_R_SUCCESS); + + /* Now check the grant policy */ for (element = cfg_list_first(policy); element != NULL; element = cfg_list_next(element)) @@ -965,24 +1163,28 @@ check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) { isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b, - dns_rootname, ISC_FALSE, NULL); + dns_rootname, 0, NULL); if (tresult != ISC_R_SUCCESS) { cfg_obj_log(identity, logctx, ISC_LOG_ERROR, "'%s' is not a valid name", str); result = tresult; } - dns_fixedname_init(&fixed); - str = cfg_obj_asstring(dname); - isc_buffer_init(&b, str, strlen(str)); - isc_buffer_add(&b, strlen(str)); - tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b, - dns_rootname, ISC_FALSE, NULL); - if (tresult != ISC_R_SUCCESS) { - cfg_obj_log(dname, logctx, ISC_LOG_ERROR, - "'%s' is not a valid name", str); - result = tresult; + if (tresult == ISC_R_SUCCESS && + strcasecmp(cfg_obj_asstring(matchtype), "zonesub") != 0) { + dns_fixedname_init(&fixed); + str = cfg_obj_asstring(dname); + isc_buffer_init(&b, str, strlen(str)); + isc_buffer_add(&b, strlen(str)); + tresult = dns_name_fromtext(dns_fixedname_name(&fixed), + &b, dns_rootname, 0, NULL); + if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(dname, logctx, ISC_LOG_ERROR, + "'%s' is not a valid name", str); + result = tresult; + } } + if (tresult == ISC_R_SUCCESS && strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 && !dns_name_iswildcard(dns_fixedname_name(&fixed))) { @@ -1020,7 +1222,8 @@ check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) { #define HINTZONE 8 #define FORWARDZONE 16 #define DELEGATIONZONE 32 -#define CHECKACL 64 +#define STATICSTUBZONE 64 +#define CHECKACL 128 typedef struct { const char *name; @@ -1033,7 +1236,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, dns_rdataclass_t defclass, cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx) { - const char *zname; + const char *znamestr; const char *typestr; unsigned int ztype; const cfg_obj_t *zoptions; @@ -1043,11 +1246,14 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, unsigned int i; dns_rdataclass_t zclass; dns_fixedname_t fixedname; + dns_name_t *zname = NULL; isc_buffer_t b; isc_boolean_t root = ISC_FALSE; + const cfg_listelt_t *element; static optionstable options[] = { - { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL }, + { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL | + STATICSTUBZONE }, { "allow-notify", SLAVEZONE | CHECKACL }, { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL }, { "notify", MASTERZONE | SLAVEZONE }, @@ -1070,12 +1276,14 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, { "min-retry-time", SLAVEZONE | STUBZONE }, { "max-refresh-time", SLAVEZONE | STUBZONE }, { "min-refresh-time", SLAVEZONE | STUBZONE }, + { "dnssec-secure-to-insecure", MASTERZONE }, { "sig-validity-interval", MASTERZONE }, { "sig-re-signing-interval", MASTERZONE }, { "sig-signing-nodes", MASTERZONE }, { "sig-signing-type", MASTERZONE }, { "sig-signing-signatures", MASTERZONE }, - { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE }, + { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE | + STATICSTUBZONE}, { "allow-update", MASTERZONE | CHECKACL }, { "allow-update-forwarding", SLAVEZONE | CHECKACL }, { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE }, @@ -1089,12 +1297,17 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, { "key-directory", MASTERZONE }, { "check-wildcard", MASTERZONE }, { "check-mx", MASTERZONE }, + { "check-dup-records", MASTERZONE }, { "integrity-check", MASTERZONE }, { "check-mx-cname", MASTERZONE }, { "check-srv-cname", MASTERZONE }, { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE }, { "update-check-ksk", MASTERZONE }, + { "dnssec-dnskey-kskonly", MASTERZONE }, + { "auto-dnssec", MASTERZONE }, { "try-tcp-refresh", SLAVEZONE }, + { "server-addresses", STATICSTUBZONE }, + { "server-names", STATICSTUBZONE }, }; static optionstable dialups[] = { @@ -1104,7 +1317,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, { "passive", SLAVEZONE | STUBZONE }, }; - zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); + znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); zoptions = cfg_tuple_get(zconfig, "options"); @@ -1112,7 +1325,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, (void)cfg_map_get(zoptions, "type", &obj); if (obj == NULL) { cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, - "zone '%s': type not present", zname); + "zone '%s': type not present", znamestr); return (ISC_R_FAILURE); } @@ -1123,6 +1336,8 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, ztype = SLAVEZONE; else if (strcasecmp(typestr, "stub") == 0) ztype = STUBZONE; + else if (strcasecmp(typestr, "static-stub") == 0) + ztype = STATICSTUBZONE; else if (strcasecmp(typestr, "forward") == 0) ztype = FORWARDZONE; else if (strcasecmp(typestr, "hint") == 0) @@ -1132,7 +1347,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, else { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "zone '%s': invalid type %s", - zname, typestr); + znamestr, typestr); return (ISC_R_FAILURE); } @@ -1146,14 +1361,14 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, if (result != ISC_R_SUCCESS) { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "zone '%s': invalid class %s", - zname, r.base); + znamestr, r.base); return (ISC_R_FAILURE); } if (zclass != defclass) { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "zone '%s': class '%s' does not " "match view/default class", - zname, r.base); + znamestr, r.base); return (ISC_R_FAILURE); } } @@ -1164,26 +1379,25 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, * deals with strings. */ dns_fixedname_init(&fixedname); - isc_buffer_init(&b, zname, strlen(zname)); - isc_buffer_add(&b, strlen(zname)); + isc_buffer_init(&b, znamestr, strlen(znamestr)); + isc_buffer_add(&b, strlen(znamestr)); tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b, - dns_rootname, ISC_TRUE, NULL); + dns_rootname, DNS_NAME_DOWNCASE, NULL); if (tresult != ISC_R_SUCCESS) { cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, - "zone '%s': is not a valid name", zname); + "zone '%s': is not a valid name", znamestr); result = ISC_R_FAILURE; } else { char namebuf[DNS_NAME_FORMATSIZE]; - dns_name_format(dns_fixedname_name(&fixedname), - namebuf, sizeof(namebuf)); + zname = dns_fixedname_name(&fixedname); + dns_name_format(zname, namebuf, sizeof(namebuf)); tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2, symtab, "zone '%s': already exists " "previous definition: %s:%u", logctx, mctx); if (tresult != ISC_R_SUCCESS) result = tresult; - if (dns_name_equal(dns_fixedname_name(&fixedname), - dns_rootname)) + if (dns_name_equal(zname, dns_rootname)) root = ISC_TRUE; } @@ -1202,13 +1416,15 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "option '%s' is not allowed " "in '%s' zone '%s'", - options[i].name, typestr, zname); + options[i].name, typestr, + znamestr); result = ISC_R_FAILURE; } else cfg_obj_log(obj, logctx, ISC_LOG_WARNING, "option '%s' is not allowed " "in '%s' zone '%s'", - options[i].name, typestr, zname); + options[i].name, typestr, + znamestr); } obj = NULL; if ((options[i].allowed & ztype) != 0 && @@ -1230,7 +1446,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) { cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR, "zone '%s': missing 'masters' entry", - zname); + znamestr); result = ISC_R_FAILURE; } else { isc_uint32_t count; @@ -1241,7 +1457,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, if (tresult == ISC_R_SUCCESS && count == 0) { cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR, "zone '%s': empty 'masters' entry", - zname); + znamestr); result = ISC_R_FAILURE; } } @@ -1251,7 +1467,10 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, * Master zones can't have both "allow-update" and "update-policy". */ if (ztype == MASTERZONE) { - isc_result_t res1, res2; + isc_result_t res1, res2, res3; + const char *arg; + isc_boolean_t ddns; + obj = NULL; res1 = cfg_map_get(zoptions, "allow-update", &obj); obj = NULL; @@ -1260,11 +1479,32 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "zone '%s': 'allow-update' is ignored " "when 'update-policy' is present", - zname); + znamestr); result = ISC_R_FAILURE; } else if (res2 == ISC_R_SUCCESS && check_update_policy(obj, logctx) != ISC_R_SUCCESS) result = ISC_R_FAILURE; + ddns = ISC_TF(res1 == ISC_R_SUCCESS || res2 == ISC_R_SUCCESS); + + obj = NULL; + arg = "off"; + res3 = cfg_map_get(zoptions, "auto-dnssec", &obj); + if (res3 == ISC_R_SUCCESS) + arg = cfg_obj_asstring(obj); + if (strcasecmp(arg, "off") != 0 && !ddns) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "'auto-dnssec %s;' requires " + "dynamic DNS to be configured in the zone", + arg); + result = ISC_R_FAILURE; + } + if (strcasecmp(arg, "create") == 0) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "'auto-dnssec create;' is not " + "yet implemented"); + result = ISC_R_FAILURE; + } + obj = NULL; res1 = cfg_map_get(zoptions, "sig-signing-type", &obj); if (res1 == ISC_R_SUCCESS) { @@ -1298,7 +1538,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, "dialup type '%s' is not " "allowed in '%s' " "zone '%s'", - str, typestr, zname); + str, typestr, znamestr); result = ISC_R_FAILURE; } break; @@ -1306,7 +1546,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, if (i == sizeof(dialups) / sizeof(dialups[0])) { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "invalid dialup type '%s' in zone " - "'%s'", str, zname); + "'%s'", str, znamestr); result = ISC_R_FAILURE; } } @@ -1330,6 +1570,78 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, result = ISC_R_FAILURE; /* + * Check validity of static stub server addresses. + */ + obj = NULL; + (void)cfg_map_get(zoptions, "server-addresses", &obj); + if (ztype == STATICSTUBZONE && obj != NULL) { + for (element = cfg_list_first(obj); + element != NULL; + element = cfg_list_next(element)) + { + isc_sockaddr_t sa; + isc_netaddr_t na; + obj = cfg_listelt_value(element); + sa = *cfg_obj_assockaddr(obj); + + if (isc_sockaddr_getport(&sa) != 0) { + result = ISC_R_FAILURE; + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "port is not configurable for " + "static stub server-addresses"); + } + + isc_netaddr_fromsockaddr(&na, &sa); + if (isc_netaddr_getzone(&na) != 0) { + result = ISC_R_FAILURE; + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "scoped address is not allowed " + "for static stub " + "server-addresses"); + } + } + } + + /* + * Check validity of static stub server names. + */ + obj = NULL; + (void)cfg_map_get(zoptions, "server-names", &obj); + if (zname != NULL && ztype == STATICSTUBZONE && obj != NULL) { + for (element = cfg_list_first(obj); + element != NULL; + element = cfg_list_next(element)) + { + const char *snamestr; + dns_fixedname_t fixed_sname; + isc_buffer_t b2; + dns_name_t *sname; + + obj = cfg_listelt_value(element); + snamestr = cfg_obj_asstring(obj); + + dns_fixedname_init(&fixed_sname); + isc_buffer_init(&b2, snamestr, strlen(snamestr)); + isc_buffer_add(&b2, strlen(snamestr)); + sname = dns_fixedname_name(&fixed_sname); + tresult = dns_name_fromtext(sname, &b2, dns_rootname, + 0, NULL); + if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, + "server-name '%s' is not a valid " + "name", snamestr); + result = ISC_R_FAILURE; + } else if (dns_name_issubdomain(sname, zname)) { + cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, + "server-name '%s' must not be a " + "subdomain of zone name '%s'", + snamestr, znamestr); + result = ISC_R_FAILURE; + } + } + } + + /* * Check various options. */ tresult = check_options(zoptions, logctx, mctx); @@ -1352,7 +1664,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, (ztype == MASTERZONE || ztype == HINTZONE)) { cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, "zone '%s': missing 'file' entry", - zname); + znamestr); result = tresult; } } @@ -1374,6 +1686,9 @@ bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) { const char *algorithm; int i; size_t len = 0; + isc_result_t result; + isc_buffer_t buf; + unsigned char secretbuf[1024]; static const algorithmtable algorithms[] = { { "hmac-md5", 128 }, { "hmac-md5.sig-alg.reg.int", 0 }, @@ -1396,6 +1711,14 @@ bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) { return (ISC_R_FAILURE); } + isc_buffer_init(&buf, secretbuf, sizeof(secretbuf)); + result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR, + "bad secret '%s'", isc_result_totext(result)); + return (result); + } + algorithm = cfg_obj_asstring(algobj); for (i = 0; algorithms[i].name != NULL; i++) { len = strlen(algorithms[i].name); @@ -1480,7 +1803,7 @@ check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab, isc_buffer_init(&b, keyid, strlen(keyid)); isc_buffer_add(&b, strlen(keyid)); tresult = dns_name_fromtext(name, &b, dns_rootname, - ISC_FALSE, NULL); + 0, NULL); if (tresult != ISC_R_SUCCESS) { cfg_obj_log(key, logctx, ISC_LOG_ERROR, "key '%s': bad key name", keyid); @@ -1650,7 +1973,7 @@ check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions, isc_buffer_add(&b, strlen(keyval)); keyname = dns_fixedname_name(&fname); tresult = dns_name_fromtext(keyname, &b, dns_rootname, - ISC_FALSE, NULL); + 0, NULL); if (tresult != ISC_R_SUCCESS) { cfg_obj_log(keys, logctx, ISC_LOG_ERROR, "bad key name '%s'", keyval); @@ -1670,7 +1993,8 @@ check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions, } static isc_result_t -check_trusted_key(const cfg_obj_t *key, isc_log_t *logctx) +check_trusted_key(const cfg_obj_t *key, isc_boolean_t managed, + isc_log_t *logctx) { const char *keystr, *keynamestr; dns_fixedname_t fkeyname; @@ -1704,6 +2028,19 @@ check_trusted_key(const cfg_obj_t *key, isc_log_t *logctx) result = ISC_R_FAILURE; } + if (managed) { + const char *initmethod; + initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init")); + + if (strcasecmp(initmethod, "initial-key") != 0) { + cfg_obj_log(key, logctx, ISC_LOG_ERROR, + "managed key '%s': " + "invalid initialization method '%s'", + keynamestr, initmethod); + result = ISC_R_FAILURE; + } + } + isc_buffer_init(&keydatabuf, keydata, sizeof(keydata)); keystr = cfg_obj_asstring(cfg_tuple_get(key, "key")); @@ -1719,7 +2056,8 @@ check_trusted_key(const cfg_obj_t *key, isc_log_t *logctx) if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) && r.length > 1 && r.base[0] == 1 && r.base[1] == 3) cfg_obj_log(key, logctx, ISC_LOG_WARNING, - "trusted key '%s' has a weak exponent", + "%s key '%s' has a weak exponent", + managed ? "managed" : "trusted", keynamestr); } @@ -1892,12 +2230,32 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, element2 != NULL; element2 = cfg_list_next(element2)) { obj = cfg_listelt_value(element2); - tresult = check_trusted_key(obj, logctx); + tresult = check_trusted_key(obj, ISC_FALSE, logctx); if (tresult != ISC_R_SUCCESS) result = tresult; } } + keys = NULL; + if (voptions != NULL) + (void)cfg_map_get(voptions, "managed-keys", &keys); + if (keys == NULL) + (void)cfg_map_get(config, "managed-keys", &keys); + + for (element = cfg_list_first(keys); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *keylist = cfg_listelt_value(element); + for (element2 = cfg_list_first(keylist); + element2 != NULL; + element2 = cfg_list_next(element2)) { + obj = cfg_listelt_value(element2); + tresult = check_trusted_key(obj, ISC_TRUE, logctx); + if (tresult != ISC_R_SUCCESS) + result = tresult; + } + } /* * Check options. */ @@ -1917,7 +2275,16 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, if (tresult != ISC_R_SUCCESS) result = tresult; - cfg_aclconfctx_destroy(&actx); + tresult = check_filteraaaa(&actx, voptions, viewname, config, + logctx, mctx); + if (tresult != ISC_R_SUCCESS) + result = tresult; + + tresult = check_dns64(&actx, voptions, config, logctx, mctx); + if (tresult != ISC_R_SUCCESS) + result = tresult; + + cfg_aclconfctx_clear(&actx); return (result); } @@ -2162,7 +2529,7 @@ bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx, result = tresult; } } - cfg_aclconfctx_destroy(&actx); + cfg_aclconfctx_clear(&actx); return (result); } diff --git a/lib/bind9/include/bind9/getaddresses.h b/lib/bind9/include/bind9/getaddresses.h index 677ced2..9ad8045 100644 --- a/lib/bind9/include/bind9/getaddresses.h +++ b/lib/bind9/include/bind9/getaddresses.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: getaddresses.h,v 1.9.332.2 2009-01-18 23:47:35 tbox Exp $ */ +/* $Id: getaddresses.h,v 1.11 2009-01-17 23:47:42 tbox Exp $ */ #ifndef BIND9_GETADDRESSES_H #define BIND9_GETADDRESSES_H 1 diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in index dfb8d7f..45c5c2a 100644 --- a/lib/dns/Makefile.in +++ b/lib/dns/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 1998-2003 Internet Software Consortium. # # Permission to use, copy, modify, and/or distribute this software for any @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.163.50.2 2010-06-09 23:48:16 tbox Exp $ +# $Id: Makefile.in,v 1.176 2011-01-13 01:59:27 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -34,8 +34,7 @@ USE_ISC_SPNEGO = @USE_ISC_SPNEGO@ CINCLUDES = -I. -Iinclude ${DNS_INCLUDES} \ ${ISC_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@ -CDEFINES = -DUSE_MD5 @USE_OPENSSL@ @USE_PKCS11@ @USE_GSSAPI@ \ - ${USE_ISC_SPNEGO} +CDEFINES = -DUSE_MD5 @USE_OPENSSL@ @USE_GSSAPI@ ${USE_ISC_SPNEGO} CWARNINGS = @@ -48,7 +47,7 @@ LIBS = @LIBS@ # Alphabetically OPENSSLLINKOBJS = openssl_link.@O@ openssldh_link.@O@ openssldsa_link.@O@ \ - opensslrsa_link.@O@ + opensslgost_link.@O@ opensslrsa_link.@O@ DSTOBJS = @DST_EXTRA_OBJS@ @OPENSSLLINKOBJS@ \ dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \ @@ -58,24 +57,26 @@ DSTOBJS = @DST_EXTRA_OBJS@ @OPENSSLLINKOBJS@ \ DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \ cache.@O@ callbacks.@O@ compress.@O@ \ db.@O@ dbiterator.@O@ dbtable.@O@ diff.@O@ dispatch.@O@ \ - dlz.@O@ dnssec.@O@ ds.@O@ forward.@O@ iptable.@O@ journal.@O@ \ - keytable.@O@ lib.@O@ log.@O@ lookup.@O@ \ + dlz.@O@ dns64.@O@ dnssec.@O@ ds.@O@ forward.@O@ iptable.@O@ \ + journal.@O@ keydata.@O@ keytable.@O@ \ + lib.@O@ log.@O@ lookup.@O@ \ master.@O@ masterdump.@O@ message.@O@ \ - name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ order.@O@ peer.@O@ portlist.@O@ \ + name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ order.@O@ peer.@O@ \ + portlist.@O@ private.@O@ \ rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rcode.@O@ rdata.@O@ \ - rdatalist.@O@ \ - rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ request.@O@ \ - resolver.@O@ result.@O@ rootns.@O@ sdb.@O@ sdlz.@O@ \ - soa.@O@ ssu.@O@ \ + rdatalist.@O@ rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ \ + request.@O@ resolver.@O@ result.@O@ rootns.@O@ rpz.@O@ \ + rriterator.@O@ sdb.@O@ \ + sdlz.@O@ soa.@O@ ssu.@O@ ssu_external.@O@ \ stats.@O@ tcpmsg.@O@ time.@O@ timer.@O@ tkey.@O@ \ - tsig.@O@ ttl.@O@ validator.@O@ \ + tsec.@O@ tsig.@O@ ttl.@O@ validator.@O@ \ version.@O@ view.@O@ xfrin.@O@ zone.@O@ zonekey.@O@ zt.@O@ OBJS= ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} # Alphabetically -OPENSSLLINKSRCS = openssl_link.c openssldh_link.c \ - openssldsa_link.c opensslrsa_link.c +OPENSSLLINKSRCS = openssl_link.c openssldh_link.c openssldsa_link.c \ + opensslgost_link.c opensslrsa_link.c DSTSRCS = @DST_EXTRA_SRCS@ @OPENSSLLINKSRCS@ \ dst_api.c dst_lib.c dst_parse.c \ @@ -85,17 +86,16 @@ DSTSRCS = @DST_EXTRA_SRCS@ @OPENSSLLINKSRCS@ \ DNSSRCS = acache.c acl.c adb.c byaddr.c \ cache.c callbacks.c compress.c \ db.c dbiterator.c dbtable.c diff.c dispatch.c \ - dlz.c dnssec.c ds.c forward.c iptable.c journal.c \ - keytable.c lib.c log.c lookup.c \ + dlz.c dns64.c dnssec.c ds.c forward.c iptable.c journal.c \ + keydata.c keytable.c lib.c log.c lookup.c \ master.c masterdump.c message.c \ name.c ncache.c nsec.c nsec3.c order.c peer.c portlist.c \ - rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c \ - rdatalist.c \ + rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c rdatalist.c \ rdataset.c rdatasetiter.c rdataslab.c request.c \ - resolver.c result.c rootns.c sdb.c sdlz.c \ - soa.c ssu.c \ + resolver.c result.c rootns.c rpz.c rriterator.c \ + sdb.c sdlz.c soa.c ssu.c ssu_external.c \ stats.c tcpmsg.c time.c timer.c tkey.c \ - tsig.c ttl.c validator.c \ + tsec.c tsig.c ttl.c validator.c \ version.c view.c xfrin.c zone.c zonekey.c zt.c ${OTHERSRCS} SRCS = ${DSTSRCS} ${DNSSRCS} diff --git a/lib/dns/acl.c b/lib/dns/acl.c index cfb7fd8..118e394 100644 --- a/lib/dns/acl.c +++ b/lib/dns/acl.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: acl.c,v 1.50.44.3 2009-01-18 23:47:35 tbox Exp $ */ +/* $Id: acl.c,v 1.53 2009-01-17 23:47:42 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/adb.c b/lib/dns/adb.c index cd9cadf..fcc2dd8 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: adb.c,v 1.243.42.6 2010-08-11 23:45:49 tbox Exp $ */ +/* $Id: adb.c,v 1.254 2010-12-21 23:47:08 tbox Exp $ */ /*! \file * @@ -66,13 +66,6 @@ #define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC) /*! - * The number of buckets needs to be a prime (for good hashing). - * - * XXXRTH How many buckets do we need? - */ -#define NBUCKETS 1009 /*%< how many buckets for names/addrs */ - -/*! * For type 3 negative cache entries, we will remember that the address is * broken for this long. XXXMLG This is also used for actual addresses, too. * The intent is to keep us from constantly asking about A/AAAA records @@ -139,30 +132,37 @@ struct dns_adb { * * XXXRTH Have a per-bucket structure that contains all of these? */ - dns_adbnamelist_t names[NBUCKETS]; - dns_adbnamelist_t deadnames[NBUCKETS]; - /*% See dns_adbnamelist_t */ - isc_mutex_t namelocks[NBUCKETS]; - /*% See dns_adbnamelist_t */ - isc_boolean_t name_sd[NBUCKETS]; - /*% See dns_adbnamelist_t */ - unsigned int name_refcnt[NBUCKETS]; + unsigned int nnames; + isc_mutex_t namescntlock; + unsigned int namescnt; + dns_adbnamelist_t *names; + dns_adbnamelist_t *deadnames; + isc_mutex_t *namelocks; + isc_boolean_t *name_sd; + unsigned int *name_refcnt; /*! - * Bucketized locks for entries. + * Bucketized locks and lists for entries. * * XXXRTH Have a per-bucket structure that contains all of these? */ - dns_adbentrylist_t entries[NBUCKETS]; - dns_adbentrylist_t deadentries[NBUCKETS]; - isc_mutex_t entrylocks[NBUCKETS]; - isc_boolean_t entry_sd[NBUCKETS]; /*%< shutting down */ - unsigned int entry_refcnt[NBUCKETS]; + unsigned int nentries; + isc_mutex_t entriescntlock; + unsigned int entriescnt; + dns_adbentrylist_t *entries; + dns_adbentrylist_t *deadentries; + isc_mutex_t *entrylocks; + isc_boolean_t *entry_sd; /*%< shutting down */ + unsigned int *entry_refcnt; isc_event_t cevent; isc_boolean_t cevent_sent; isc_boolean_t shutting_down; isc_eventlist_t whenshutdown; + isc_event_t growentries; + isc_boolean_t growentries_sent; + isc_event_t grownames; + isc_boolean_t grownames_sent; }; /* @@ -484,6 +484,322 @@ ttlclamp(dns_ttl_t ttl) { } /* + * Hashing is most efficient if the number of buckets is prime. + * The sequence below is the closest previous primes to 2^n and + * 1.5 * 2^n, for values of n from 10 to 28. (The tables will + * no longer grow beyond 2^28 entries.) + */ +static const unsigned nbuckets[] = { 1021, 1531, 2039, 3067, 4093, 6143, + 8191, 12281, 16381, 24571, 32749, + 49193, 65521, 98299, 131071, 199603, + 262139, 393209, 524287, 768431, 1048573, + 1572853, 2097143, 3145721, 4194301, + 6291449, 8388593, 12582893, 16777213, + 25165813, 33554393, 50331599, 67108859, + 100663291, 134217689, 201326557, + 268535431, 0 }; + +static void +grow_entries(isc_task_t *task, isc_event_t *ev) { + dns_adb_t *adb; + dns_adbentry_t *e; + dns_adbentrylist_t *newdeadentries = NULL; + dns_adbentrylist_t *newentries = NULL; + isc_boolean_t *newentry_sd = NULL; + isc_mutex_t *newentrylocks = NULL; + isc_result_t result; + unsigned int *newentry_refcnt = NULL; + unsigned int i, n, bucket; + + adb = ev->ev_arg; + INSIST(DNS_ADB_VALID(adb)); + + isc_event_free(&ev); + + isc_task_beginexclusive(task); + + i = 0; + while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i]) + i++; + if (nbuckets[i] != 0) + n = nbuckets[i]; + else + goto done; + + DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n); + + /* + * Are we shutting down? + */ + for (i = 0; i < adb->nentries; i++) + if (adb->entry_sd[i]) + goto cleanup; + + /* + * Grab all the resources we need. + */ + newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n); + newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n); + newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n); + newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n); + newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n); + if (newentries == NULL || newdeadentries == NULL || + newentrylocks == NULL || newentry_sd == NULL || + newentry_refcnt == NULL) + goto cleanup; + + /* + * Initialise the new resources. + */ + result = isc_mutexblock_init(newentrylocks, n); + if (result != ISC_R_SUCCESS) + goto cleanup; + + for (i = 0; i < n; i++) { + ISC_LIST_INIT(newentries[i]); + ISC_LIST_INIT(newdeadentries[i]); + newentry_sd[i] = ISC_FALSE; + newentry_refcnt[i] = 0; + adb->irefcnt++; + } + + /* + * Move entries to new arrays. + */ + for (i = 0; i < adb->nentries; i++) { + e = ISC_LIST_HEAD(adb->entries[i]); + while (e != NULL) { + ISC_LIST_UNLINK(adb->entries[i], e, plink); + bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n; + e->lock_bucket = bucket; + ISC_LIST_APPEND(newentries[bucket], e, plink); + INSIST(adb->entry_refcnt[i] > 0); + adb->entry_refcnt[i]--; + newentry_refcnt[bucket]++; + e = ISC_LIST_HEAD(adb->entries[i]); + } + e = ISC_LIST_HEAD(adb->deadentries[i]); + while (e != NULL) { + ISC_LIST_UNLINK(adb->deadentries[i], e, plink); + bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n; + e->lock_bucket = bucket; + ISC_LIST_APPEND(newdeadentries[bucket], e, plink); + INSIST(adb->entry_refcnt[i] > 0); + adb->entry_refcnt[i]--; + newentry_refcnt[bucket]++; + e = ISC_LIST_HEAD(adb->deadentries[i]); + } + INSIST(adb->entry_refcnt[i] == 0); + adb->irefcnt--; + } + + /* + * Cleanup old resources. + */ + DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries); + isc_mem_put(adb->mctx, adb->entries, + sizeof(*adb->entries) * adb->nentries); + isc_mem_put(adb->mctx, adb->deadentries, + sizeof(*adb->deadentries) * adb->nentries); + isc_mem_put(adb->mctx, adb->entrylocks, + sizeof(*adb->entrylocks) * adb->nentries); + isc_mem_put(adb->mctx, adb->entry_sd, + sizeof(*adb->entry_sd) * adb->nentries); + isc_mem_put(adb->mctx, adb->entry_refcnt, + sizeof(*adb->entry_refcnt) * adb->nentries); + + /* + * Install new resources. + */ + adb->entries = newentries; + adb->deadentries = newdeadentries; + adb->entrylocks = newentrylocks; + adb->entry_sd = newentry_sd; + adb->entry_refcnt = newentry_refcnt; + adb->nentries = n; + + /* + * Only on success do we set adb->growentries_sent to ISC_FALSE. + * This will prevent us being continuously being called on error. + */ + adb->growentries_sent = ISC_FALSE; + goto done; + + cleanup: + if (newentries != NULL) + isc_mem_put(adb->mctx, newentries, + sizeof(*newentries) * n); + if (newdeadentries != NULL) + isc_mem_put(adb->mctx, newdeadentries, + sizeof(*newdeadentries) * n); + if (newentrylocks != NULL) + isc_mem_put(adb->mctx, newentrylocks, + sizeof(*newentrylocks) * n); + if (newentry_sd != NULL) + isc_mem_put(adb->mctx, newentry_sd, + sizeof(*newentry_sd) * n); + if (newentry_refcnt != NULL) + isc_mem_put(adb->mctx, newentry_refcnt, + sizeof(*newentry_refcnt) * n); + done: + isc_task_endexclusive(task); + + LOCK(&adb->lock); + if (dec_adb_irefcnt(adb)) + check_exit(adb); + UNLOCK(&adb->lock); + DP(ISC_LOG_INFO, "adb: grow_entries finished"); +} + +static void +grow_names(isc_task_t *task, isc_event_t *ev) { + dns_adb_t *adb; + dns_adbname_t *name; + dns_adbnamelist_t *newdeadnames = NULL; + dns_adbnamelist_t *newnames = NULL; + isc_boolean_t *newname_sd = NULL; + isc_mutex_t *newnamelocks = NULL; + isc_result_t result; + unsigned int *newname_refcnt = NULL; + unsigned int i, n, bucket; + + adb = ev->ev_arg; + INSIST(DNS_ADB_VALID(adb)); + + isc_event_free(&ev); + + isc_task_beginexclusive(task); + + i = 0; + while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i]) + i++; + if (nbuckets[i] != 0) + n = nbuckets[i]; + else + goto done; + + DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n); + + /* + * Are we shutting down? + */ + for (i = 0; i < adb->nnames; i++) + if (adb->name_sd[i]) + goto cleanup; + + /* + * Grab all the resources we need. + */ + newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n); + newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n); + newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n); + newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n); + newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n); + if (newnames == NULL || newdeadnames == NULL || + newnamelocks == NULL || newname_sd == NULL || + newname_refcnt == NULL) + goto cleanup; + + /* + * Initialise the new resources. + */ + result = isc_mutexblock_init(newnamelocks, n); + if (result != ISC_R_SUCCESS) + goto cleanup; + + for (i = 0; i < n; i++) { + ISC_LIST_INIT(newnames[i]); + ISC_LIST_INIT(newdeadnames[i]); + newname_sd[i] = ISC_FALSE; + newname_refcnt[i] = 0; + adb->irefcnt++; + } + + /* + * Move names to new arrays. + */ + for (i = 0; i < adb->nnames; i++) { + name = ISC_LIST_HEAD(adb->names[i]); + while (name != NULL) { + ISC_LIST_UNLINK(adb->names[i], name, plink); + bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n; + name->lock_bucket = bucket; + ISC_LIST_APPEND(newnames[bucket], name, plink); + INSIST(adb->name_refcnt[i] > 0); + adb->name_refcnt[i]--; + newname_refcnt[bucket]++; + name = ISC_LIST_HEAD(adb->names[i]); + } + name = ISC_LIST_HEAD(adb->deadnames[i]); + while (name != NULL) { + ISC_LIST_UNLINK(adb->deadnames[i], name, plink); + bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n; + name->lock_bucket = bucket; + ISC_LIST_APPEND(newdeadnames[bucket], name, plink); + INSIST(adb->name_refcnt[i] > 0); + adb->name_refcnt[i]--; + newname_refcnt[bucket]++; + name = ISC_LIST_HEAD(adb->deadnames[i]); + } + INSIST(adb->name_refcnt[i] == 0); + adb->irefcnt--; + } + + /* + * Cleanup old resources. + */ + DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames); + isc_mem_put(adb->mctx, adb->names, + sizeof(*adb->names) * adb->nnames); + isc_mem_put(adb->mctx, adb->deadnames, + sizeof(*adb->deadnames) * adb->nnames); + isc_mem_put(adb->mctx, adb->namelocks, + sizeof(*adb->namelocks) * adb->nnames); + isc_mem_put(adb->mctx, adb->name_sd, + sizeof(*adb->name_sd) * adb->nnames); + isc_mem_put(adb->mctx, adb->name_refcnt, + sizeof(*adb->name_refcnt) * adb->nnames); + + /* + * Install new resources. + */ + adb->names = newnames; + adb->deadnames = newdeadnames; + adb->namelocks = newnamelocks; + adb->name_sd = newname_sd; + adb->name_refcnt = newname_refcnt; + adb->nnames = n; + + /* + * Only on success do we set adb->grownames_sent to ISC_FALSE. + * This will prevent us being continuously being called on error. + */ + adb->grownames_sent = ISC_FALSE; + goto done; + + cleanup: + if (newnames != NULL) + isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n); + if (newdeadnames != NULL) + isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n); + if (newnamelocks != NULL) + isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n); + if (newname_sd != NULL) + isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n); + if (newname_refcnt != NULL) + isc_mem_put(adb->mctx, newname_refcnt, + sizeof(*newname_refcnt) * n); + done: + isc_task_endexclusive(task); + + LOCK(&adb->lock); + if (dec_adb_irefcnt(adb)) + check_exit(adb); + UNLOCK(&adb->lock); + DP(ISC_LOG_INFO, "adb: grow_names finished"); +} + +/* * Requires the adbname bucket be locked and that no entry buckets be locked. * * This code handles A and AAAA rdatasets only. @@ -836,12 +1152,12 @@ violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) { */ static isc_boolean_t shutdown_names(dns_adb_t *adb) { - int bucket; + unsigned int bucket; isc_boolean_t result = ISC_FALSE; dns_adbname_t *name; dns_adbname_t *next_name; - for (bucket = 0; bucket < NBUCKETS; bucket++) { + for (bucket = 0; bucket < adb->nnames; bucket++) { LOCK(&adb->namelocks[bucket]); adb->name_sd[bucket] = ISC_TRUE; @@ -881,12 +1197,12 @@ shutdown_names(dns_adb_t *adb) { */ static isc_boolean_t shutdown_entries(dns_adb_t *adb) { - int bucket; + unsigned int bucket; isc_boolean_t result = ISC_FALSE; dns_adbentry_t *entry; dns_adbentry_t *next_entry; - for (bucket = 0; bucket < NBUCKETS; bucket++) { + for (bucket = 0; bucket < adb->nentries; bucket++) { LOCK(&adb->entrylocks[bucket]); adb->entry_sd[bucket] = ISC_TRUE; @@ -1306,6 +1622,16 @@ new_adbname(dns_adb_t *adb, dns_name_t *dnsname) { ISC_LIST_INIT(name->finds); ISC_LINK_INIT(name, plink); + LOCK(&adb->namescntlock); + adb->namescnt++; + if (!adb->grownames_sent && adb->namescnt > (adb->nnames * 8)) { + isc_event_t *event = &adb->grownames; + inc_adb_irefcnt(adb); + isc_task_send(adb->task, &event); + adb->grownames_sent = ISC_TRUE; + } + UNLOCK(&adb->namescntlock); + return (name); } @@ -1329,6 +1655,9 @@ free_adbname(dns_adb_t *adb, dns_adbname_t **name) { dns_name_free(&n->name, adb->mctx); isc_mempool_put(adb->nmp, n); + LOCK(&adb->namescntlock); + adb->namescnt--; + UNLOCK(&adb->namescntlock); } static inline dns_adbnamehook_t * @@ -1417,6 +1746,16 @@ new_adbentry(dns_adb_t *adb) { e->expires = 0; ISC_LIST_INIT(e->lameinfo); ISC_LINK_INIT(e, plink); + LOCK(&adb->entriescntlock); + adb->entriescnt++; + if (!adb->growentries_sent && + adb->entriescnt > (adb->nentries * 8)) { + isc_event_t *event = &adb->growentries; + inc_adb_irefcnt(adb); + isc_task_send(adb->task, &event); + adb->growentries_sent = ISC_TRUE; + } + UNLOCK(&adb->entriescntlock); return (e); } @@ -1444,6 +1783,9 @@ free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) { } isc_mempool_put(adb->emp, e); + LOCK(&adb->entriescntlock); + adb->entriescnt--; + UNLOCK(&adb->entriescntlock); } static inline dns_adbfind_t * @@ -1597,7 +1939,7 @@ find_name_and_lock(dns_adb_t *adb, dns_name_t *name, dns_adbname_t *adbname; int bucket; - bucket = dns_name_fullhash(name, ISC_FALSE) % NBUCKETS; + bucket = dns_name_fullhash(name, ISC_FALSE) % adb->nnames; if (*bucketp == DNS_ADB_INVALIDBUCKET) { LOCK(&adb->namelocks[bucket]); @@ -1639,7 +1981,7 @@ find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp, dns_adbentry_t *entry, *entry_next; int bucket; - bucket = isc_sockaddr_hash(addr, ISC_TRUE) % NBUCKETS; + bucket = isc_sockaddr_hash(addr, ISC_TRUE) % adb->nentries; if (*bucketp == DNS_ADB_INVALIDBUCKET) { LOCK(&adb->entrylocks[bucket]); @@ -1992,13 +2334,36 @@ destroy(dns_adb_t *adb) { isc_mempool_destroy(&adb->aimp); isc_mempool_destroy(&adb->afmp); - DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS); - DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS); + DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries); + isc_mem_put(adb->mctx, adb->entries, + sizeof(*adb->entries) * adb->nentries); + isc_mem_put(adb->mctx, adb->deadentries, + sizeof(*adb->deadentries) * adb->nentries); + isc_mem_put(adb->mctx, adb->entrylocks, + sizeof(*adb->entrylocks) * adb->nentries); + isc_mem_put(adb->mctx, adb->entry_sd, + sizeof(*adb->entry_sd) * adb->nentries); + isc_mem_put(adb->mctx, adb->entry_refcnt, + sizeof(*adb->entry_refcnt) * adb->nentries); + + DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames); + isc_mem_put(adb->mctx, adb->names, + sizeof(*adb->names) * adb->nnames); + isc_mem_put(adb->mctx, adb->deadnames, + sizeof(*adb->deadnames) * adb->nnames); + isc_mem_put(adb->mctx, adb->namelocks, + sizeof(*adb->namelocks) * adb->nnames); + isc_mem_put(adb->mctx, adb->name_sd, + sizeof(*adb->name_sd) * adb->nnames); + isc_mem_put(adb->mctx, adb->name_refcnt, + sizeof(*adb->name_refcnt) * adb->nnames); DESTROYLOCK(&adb->reflock); DESTROYLOCK(&adb->lock); DESTROYLOCK(&adb->mplock); DESTROYLOCK(&adb->overmemlock); + DESTROYLOCK(&adb->entriescntlock); + DESTROYLOCK(&adb->namescntlock); isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t)); } @@ -2014,7 +2379,7 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, { dns_adb_t *adb; isc_result_t result; - int i; + unsigned int i; REQUIRE(mem != NULL); REQUIRE(view != NULL); @@ -2054,6 +2419,30 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, adb->shutting_down = ISC_FALSE; ISC_LIST_INIT(adb->whenshutdown); + adb->nentries = nbuckets[0]; + adb->entriescnt = 0; + adb->entries = NULL; + adb->deadentries = NULL; + adb->entry_sd = NULL; + adb->entry_refcnt = NULL; + adb->entrylocks = NULL; + ISC_EVENT_INIT(&adb->growentries, sizeof(adb->growentries), 0, NULL, + DNS_EVENT_ADBGROWENTRIES, grow_entries, adb, + adb, NULL, NULL); + adb->growentries_sent = ISC_FALSE; + + adb->nnames = nbuckets[0]; + adb->namescnt = 0; + adb->names = NULL; + adb->deadnames = NULL; + adb->name_sd = NULL; + adb->name_refcnt = NULL; + adb->namelocks = NULL; + ISC_EVENT_INIT(&adb->grownames, sizeof(adb->grownames), 0, NULL, + DNS_EVENT_ADBGROWNAMES, grow_names, adb, + adb, NULL, NULL); + adb->grownames_sent = ISC_FALSE; + isc_mem_attach(mem, &adb->mctx); result = isc_mutex_init(&adb->lock); @@ -2072,28 +2461,68 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, if (result != ISC_R_SUCCESS) goto fail0e; + result = isc_mutex_init(&adb->entriescntlock); + if (result != ISC_R_SUCCESS) + goto fail0f; + + result = isc_mutex_init(&adb->namescntlock); + if (result != ISC_R_SUCCESS) + goto fail0g; + +#define ALLOCENTRY(adb, el) \ + do { \ + (adb)->el = isc_mem_get((adb)->mctx, \ + sizeof(*(adb)->el) * (adb)->nentries); \ + if ((adb)->el == NULL) { \ + result = ISC_R_NOMEMORY; \ + goto fail1; \ + }\ + } while (0) + ALLOCENTRY(adb, entries); + ALLOCENTRY(adb, deadentries); + ALLOCENTRY(adb, entrylocks); + ALLOCENTRY(adb, entry_sd); + ALLOCENTRY(adb, entry_refcnt); +#undef ALLOCENTRY + +#define ALLOCNAME(adb, el) \ + do { \ + (adb)->el = isc_mem_get((adb)->mctx, \ + sizeof(*(adb)->el) * (adb)->nnames); \ + if ((adb)->el == NULL) { \ + result = ISC_R_NOMEMORY; \ + goto fail1; \ + }\ + } while (0) + ALLOCNAME(adb, names); + ALLOCNAME(adb, deadnames); + ALLOCNAME(adb, namelocks); + ALLOCNAME(adb, name_sd); + ALLOCNAME(adb, name_refcnt); +#undef ALLOCNAME + /* * Initialize the bucket locks for names and elements. * May as well initialize the list heads, too. */ - result = isc_mutexblock_init(adb->namelocks, NBUCKETS); + result = isc_mutexblock_init(adb->namelocks, adb->nnames); if (result != ISC_R_SUCCESS) goto fail1; - for (i = 0; i < NBUCKETS; i++) { + for (i = 0; i < adb->nnames; i++) { ISC_LIST_INIT(adb->names[i]); ISC_LIST_INIT(adb->deadnames[i]); adb->name_sd[i] = ISC_FALSE; adb->name_refcnt[i] = 0; adb->irefcnt++; } - for (i = 0; i < NBUCKETS; i++) { + for (i = 0; i < adb->nentries; i++) { ISC_LIST_INIT(adb->entries[i]); ISC_LIST_INIT(adb->deadentries[i]); adb->entry_sd[i] = ISC_FALSE; adb->entry_refcnt[i] = 0; adb->irefcnt++; } - result = isc_mutexblock_init(adb->entrylocks, NBUCKETS); + result = isc_mutexblock_init(adb->entrylocks, adb->nentries); if (result != ISC_R_SUCCESS) goto fail2; @@ -2140,12 +2569,42 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, isc_task_detach(&adb->task); /* clean up entrylocks */ - DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS); + DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries); fail2: /* clean up namelocks */ - DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS); + DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames); fail1: /* clean up only allocated memory */ + if (adb->entries != NULL) + isc_mem_put(adb->mctx, adb->entries, + sizeof(*adb->entries) * adb->nentries); + if (adb->deadentries != NULL) + isc_mem_put(adb->mctx, adb->deadentries, + sizeof(*adb->deadentries) * adb->nentries); + if (adb->entrylocks != NULL) + isc_mem_put(adb->mctx, adb->entrylocks, + sizeof(*adb->entrylocks) * adb->nentries); + if (adb->entry_sd != NULL) + isc_mem_put(adb->mctx, adb->entry_sd, + sizeof(*adb->entry_sd) * adb->nentries); + if (adb->entry_refcnt != NULL) + isc_mem_put(adb->mctx, adb->entry_refcnt, + sizeof(*adb->entry_refcnt) * adb->nentries); + if (adb->names != NULL) + isc_mem_put(adb->mctx, adb->names, + sizeof(*adb->names) * adb->nnames); + if (adb->deadnames != NULL) + isc_mem_put(adb->mctx, adb->deadnames, + sizeof(*adb->deadnames) * adb->nnames); + if (adb->namelocks != NULL) + isc_mem_put(adb->mctx, adb->namelocks, + sizeof(*adb->namelocks) * adb->nnames); + if (adb->name_sd != NULL) + isc_mem_put(adb->mctx, adb->name_sd, + sizeof(*adb->name_sd) * adb->nnames); + if (adb->name_refcnt != NULL) + isc_mem_put(adb->mctx, adb->name_refcnt, + sizeof(*adb->name_refcnt) * adb->nnames); if (adb->nmp != NULL) isc_mempool_destroy(&adb->nmp); if (adb->nhmp != NULL) @@ -2161,6 +2620,10 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, if (adb->afmp != NULL) isc_mempool_destroy(&adb->afmp); + DESTROYLOCK(&adb->namescntlock); + fail0g: + DESTROYLOCK(&adb->entriescntlock); + fail0f: DESTROYLOCK(&adb->overmemlock); fail0e: DESTROYLOCK(&adb->reflock); @@ -2728,7 +3191,7 @@ dns_adb_cancelfind(dns_adbfind_t *find) { void dns_adb_dump(dns_adb_t *adb, FILE *f) { - int i; + unsigned int i; isc_stdtime_t now; REQUIRE(DNS_ADB_VALID(adb)); @@ -2744,9 +3207,9 @@ dns_adb_dump(dns_adb_t *adb, FILE *f) { LOCK(&adb->lock); isc_stdtime_get(&now); - for (i = 0; i < NBUCKETS; i++) + for (i = 0; i < adb->nnames; i++) RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE); - for (i = 0; i < NBUCKETS; i++) + for (i = 0; i < adb->nentries; i++) RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE); dump_adb(adb, f, ISC_FALSE, now); @@ -2762,7 +3225,7 @@ dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) { static void dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) { - int i; + unsigned int i; dns_adbname_t *name; dns_adbentry_t *entry; @@ -2772,15 +3235,15 @@ dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) { adb, adb->erefcnt, adb->irefcnt, isc_mempool_getallocated(adb->nhmp)); - for (i = 0; i < NBUCKETS; i++) + for (i = 0; i < adb->nnames; i++) LOCK(&adb->namelocks[i]); - for (i = 0; i < NBUCKETS; i++) + for (i = 0; i < adb->nentries; i++) LOCK(&adb->entrylocks[i]); /* * Dump the names */ - for (i = 0; i < NBUCKETS; i++) { + for (i = 0; i < adb->nnames; i++) { name = ISC_LIST_HEAD(adb->names[i]); if (name == NULL) continue; @@ -2824,7 +3287,7 @@ dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) { fprintf(f, ";\n; Unassociated entries\n;\n"); - for (i = 0; i < NBUCKETS; i++) { + for (i = 0; i < adb->nentries; i++) { entry = ISC_LIST_HEAD(adb->entries[i]); while (entry != NULL) { if (entry->refcnt == 0) @@ -2836,9 +3299,9 @@ dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) { /* * Unlock everything */ - for (i = 0; i < NBUCKETS; i++) + for (i = 0; i < adb->nentries; i++) UNLOCK(&adb->entrylocks[i]); - for (i = 0; i < NBUCKETS; i++) + for (i = 0; i < adb->nnames; i++) UNLOCK(&adb->namelocks[i]); } @@ -2999,10 +3462,20 @@ dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype) else adbname->fetch6_err = FIND_ERR_UNEXPECTED; - result = dns_view_find(adb->view, &adbname->name, rdtype, now, - NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0, - ISC_TF(NAME_HINTOK(adbname)), - NULL, NULL, fname, &rdataset, NULL); + /* + * We need to specify whether to search static-stub zones (if + * configured) depending on whether this is a "start at zone" lookup, + * i.e., whether it's a "bailiwick" glue. If it's bailiwick (in which + * case NAME_STARTATZONE is set) we need to stop the search at any + * matching static-stub zone without looking into the cache to honor + * the configuration on which server we should send queries to. + */ + result = dns_view_find2(adb->view, &adbname->name, rdtype, now, + NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0, + ISC_TF(NAME_HINTOK(adbname)), + (adbname->flags & NAME_STARTATZONE) != 0 ? + ISC_TRUE : ISC_FALSE, + NULL, NULL, fname, &rdataset, NULL); /* XXXVIX this switch statement is too sparse to gen a jump table. */ switch (result) { @@ -3557,9 +4030,9 @@ dns_adb_flush(dns_adb_t *adb) { /* * Call our cleanup routines. */ - for (i = 0; i < NBUCKETS; i++) + for (i = 0; i < adb->nnames; i++) RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE); - for (i = 0; i < NBUCKETS; i++) + for (i = 0; i < adb->nentries; i++) RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE); #ifdef DUMP_ADB_AFTER_CLEANING @@ -3578,7 +4051,7 @@ dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) { INSIST(DNS_ADB_VALID(adb)); LOCK(&adb->lock); - bucket = dns_name_hash(name, ISC_FALSE) % NBUCKETS; + bucket = dns_name_hash(name, ISC_FALSE) % adb->nnames; LOCK(&adb->namelocks[bucket]); adbname = ISC_LIST_HEAD(adb->names[bucket]); while (adbname != NULL) { diff --git a/lib/dns/api b/lib/dns/api index 87c3c90..9bac060 100644 --- a/lib/dns/api +++ b/lib/dns/api @@ -1,3 +1,3 @@ -LIBINTERFACE = 59 -LIBREVISION = 5 +LIBINTERFACE = 82 +LIBREVISION = 3 LIBAGE = 1 diff --git a/lib/dns/byaddr.c b/lib/dns/byaddr.c index 96b9f38..2fd61a2 100644 --- a/lib/dns/byaddr.c +++ b/lib/dns/byaddr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: byaddr.c,v 1.39 2007-06-19 23:47:16 tbox Exp $ */ +/* $Id: byaddr.c,v 1.41 2009-09-02 23:48:02 tbox Exp $ */ /*! \file */ @@ -43,25 +43,6 @@ * XXXRTH We could use a static event... */ -struct dns_byaddr { - /* Unlocked. */ - unsigned int magic; - isc_mem_t * mctx; - isc_mutex_t lock; - dns_fixedname_t name; - /* Locked by lock. */ - unsigned int options; - dns_lookup_t * lookup; - isc_task_t * task; - dns_byaddrevent_t * event; - isc_boolean_t canceled; -}; - -#define BYADDR_MAGIC ISC_MAGIC('B', 'y', 'A', 'd') -#define VALID_BYADDR(b) ISC_MAGIC_VALID(b, BYADDR_MAGIC) - -#define MAX_RESTARTS 16 - static char hex_digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' @@ -125,10 +106,29 @@ dns_byaddr_createptrname2(isc_netaddr_t *address, unsigned int options, len = (unsigned int)strlen(textname); isc_buffer_init(&buffer, textname, len); isc_buffer_add(&buffer, len); - return (dns_name_fromtext(name, &buffer, dns_rootname, - ISC_FALSE, NULL)); + return (dns_name_fromtext(name, &buffer, dns_rootname, 0, NULL)); } +#ifdef BIND9 +struct dns_byaddr { + /* Unlocked. */ + unsigned int magic; + isc_mem_t * mctx; + isc_mutex_t lock; + dns_fixedname_t name; + /* Locked by lock. */ + unsigned int options; + dns_lookup_t * lookup; + isc_task_t * task; + dns_byaddrevent_t * event; + isc_boolean_t canceled; +}; + +#define BYADDR_MAGIC ISC_MAGIC('B', 'y', 'A', 'd') +#define VALID_BYADDR(b) ISC_MAGIC_VALID(b, BYADDR_MAGIC) + +#define MAX_RESTARTS 16 + static inline isc_result_t copy_ptr_targets(dns_byaddr_t *byaddr, dns_rdataset_t *rdataset) { isc_result_t result; @@ -314,3 +314,4 @@ dns_byaddr_destroy(dns_byaddr_t **byaddrp) { *byaddrp = NULL; } +#endif /* BIND9 */ diff --git a/lib/dns/cache.c b/lib/dns/cache.c index 28ead66..bf93da2 100644 --- a/lib/dns/cache.c +++ b/lib/dns/cache.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cache.c,v 1.80.50.3 2009-05-06 23:34:30 jinmei Exp $ */ +/* $Id: cache.c,v 1.87 2009-11-12 23:43:02 each Exp $ */ /*! \file */ @@ -122,6 +122,7 @@ struct dns_cache { isc_mutex_t lock; isc_mutex_t filelock; isc_mem_t *mctx; + char *name; /* Locked by 'lock'. */ int references; @@ -132,6 +133,7 @@ struct dns_cache { char *db_type; int db_argc; char **db_argv; + isc_uint32_t size; /* Locked by 'filelock'. */ char *filename; @@ -171,6 +173,16 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, const char *db_type, unsigned int db_argc, char **db_argv, dns_cache_t **cachep) { + return (dns_cache_create2(mctx, taskmgr, timermgr, rdclass, "", + db_type, db_argc, db_argv, cachep)); +} + +isc_result_t +dns_cache_create2(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + isc_timermgr_t *timermgr, dns_rdataclass_t rdclass, + const char *cachename, const char *db_type, + unsigned int db_argc, char **db_argv, dns_cache_t **cachep) +{ isc_result_t result; dns_cache_t *cache; int i; @@ -179,6 +191,7 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, REQUIRE(cachep != NULL); REQUIRE(*cachep == NULL); REQUIRE(mctx != NULL); + REQUIRE(cachename != NULL); cache = isc_mem_get(mctx, sizeof(*cache)); if (cache == NULL) @@ -187,6 +200,15 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, cache->mctx = NULL; isc_mem_attach(mctx, &cache->mctx); + cache->name = NULL; + if (cachename != NULL) { + cache->name = isc_mem_strdup(mctx, cachename); + if (cache->name == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_mem; + } + } + result = isc_mutex_init(&cache->lock); if (result != ISC_R_SUCCESS) goto cleanup_mem; @@ -275,6 +297,8 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, cleanup_lock: DESTROYLOCK(&cache->lock); cleanup_mem: + if (cache->name != NULL) + isc_mem_free(mctx, cache->name); isc_mem_put(mctx, cache, sizeof(*cache)); isc_mem_detach(&mctx); return (result); @@ -323,6 +347,9 @@ cache_free(dns_cache_t *cache) { if (cache->db_type != NULL) isc_mem_free(cache->mctx, cache->db_type); + if (cache->name != NULL) + isc_mem_free(cache->mctx, cache->name); + DESTROYLOCK(&cache->lock); DESTROYLOCK(&cache->filelock); cache->magic = 0; @@ -423,6 +450,7 @@ dns_cache_setfilename(dns_cache_t *cache, const char *filename) { return (ISC_R_SUCCESS); } +#ifdef BIND9 isc_result_t dns_cache_load(dns_cache_t *cache) { isc_result_t result; @@ -438,22 +466,29 @@ dns_cache_load(dns_cache_t *cache) { return (result); } +#endif /* BIND9 */ isc_result_t dns_cache_dump(dns_cache_t *cache) { +#ifdef BIND9 isc_result_t result; +#endif REQUIRE(VALID_CACHE(cache)); if (cache->filename == NULL) return (ISC_R_SUCCESS); +#ifdef BIND9 LOCK(&cache->filelock); result = dns_master_dump(cache->mctx, cache->db, NULL, &dns_master_style_cache, cache->filename); UNLOCK(&cache->filelock); - return (result); +#else + return (ISC_R_NOTIMPLEMENTED); +#endif + } void @@ -493,6 +528,26 @@ dns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int t) { UNLOCK(&cache->lock); } +unsigned int +dns_cache_getcleaninginterval(dns_cache_t *cache) { + unsigned int t; + + REQUIRE(VALID_CACHE(cache)); + + LOCK(&cache->lock); + t = cache->cleaner.cleaning_interval; + UNLOCK(&cache->lock); + + return (t); +} + +const char * +dns_cache_getname(dns_cache_t *cache) { + REQUIRE(VALID_CACHE(cache)); + + return (cache->name); +} + /* * Initialize the cache cleaner object at *cleaner. * Space for the object must be allocated by the caller. @@ -519,6 +574,7 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr, cleaner->cleaning_timer = NULL; cleaner->resched_event = NULL; cleaner->overmem_event = NULL; + cleaner->cleaning_interval = 0; /* Initially turned off. */ result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE, &cleaner->iterator); @@ -547,7 +603,6 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr, goto cleanup; } - cleaner->cleaning_interval = 0; /* Initially turned off. */ result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL, cleaner->task, cleaning_timer_action, cleaner, @@ -949,6 +1004,10 @@ dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size) { if (size != 0 && size < DNS_CACHE_MINSIZE) size = DNS_CACHE_MINSIZE; + LOCK(&cache->lock); + cache->size = size; + UNLOCK(&cache->lock); + hiwater = size - (size >> 3); /* Approximately 7/8ths. */ lowater = size - (size >> 2); /* Approximately 3/4ths. */ @@ -972,6 +1031,19 @@ dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size) { isc_mem_setwater(cache->mctx, water, cache, hiwater, lowater); } +isc_uint32_t +dns_cache_getcachesize(dns_cache_t *cache) { + isc_uint32_t size; + + REQUIRE(VALID_CACHE(cache)); + + LOCK(&cache->lock); + size = cache->size; + UNLOCK(&cache->lock); + + return (size); +} + /* * The cleaner task is shutting down; do the necessary cleanup. */ diff --git a/lib/dns/client.c b/lib/dns/client.c new file mode 100644 index 0000000..e55ea1f --- /dev/null +++ b/lib/dns/client.c @@ -0,0 +1,3019 @@ +/* + * Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: client.c,v 1.12 2010-12-03 12:03:22 marka Exp $ */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c') +#define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC) + +#define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x') +#define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC) + +#define REQCTX_MAGIC ISC_MAGIC('R', 'q', 'c', 'x') +#define REQCTX_VALID(c) ISC_MAGIC_VALID(c, REQCTX_MAGIC) + +#define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x') +#define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC) + +#define MAX_RESTARTS 16 + +/*% + * DNS client object + */ +struct dns_client { + /* Unlocked */ + unsigned int magic; + unsigned int attributes; + isc_mutex_t lock; + isc_mem_t *mctx; + isc_appctx_t *actx; + isc_taskmgr_t *taskmgr; + isc_task_t *task; + isc_socketmgr_t *socketmgr; + isc_timermgr_t *timermgr; + dns_dispatchmgr_t *dispatchmgr; + dns_dispatch_t *dispatchv4; + dns_dispatch_t *dispatchv6; + + unsigned int update_timeout; + unsigned int update_udptimeout; + unsigned int update_udpretries; + unsigned int find_timeout; + unsigned int find_udpretries; + + /* Locked */ + unsigned int references; + dns_viewlist_t viewlist; + ISC_LIST(struct resctx) resctxs; + ISC_LIST(struct reqctx) reqctxs; + ISC_LIST(struct updatectx) updatectxs; +}; + +/*% + * Timeout/retry constants for dynamic update borrowed from nsupdate + */ +#define DEF_UPDATE_TIMEOUT 300 +#define MIN_UPDATE_TIMEOUT 30 +#define DEF_UPDATE_UDPTIMEOUT 3 +#define DEF_UPDATE_UDPRETRIES 3 + +#define DEF_FIND_TIMEOUT 5 +#define DEF_FIND_UDPRETRIES 3 + +#define DNS_CLIENTATTR_OWNCTX 0x01 + +#define DNS_CLIENTVIEW_NAME "dnsclient" + +/*% + * Internal state for a single name resolution procedure + */ +typedef struct resctx { + /* Unlocked */ + unsigned int magic; + isc_mutex_t lock; + dns_client_t *client; + isc_boolean_t want_dnssec; + + /* Locked */ + ISC_LINK(struct resctx) link; + isc_task_t *task; + dns_view_t *view; + unsigned int restarts; + dns_fixedname_t name; + dns_rdatatype_t type; + dns_fetch_t *fetch; + dns_namelist_t namelist; + isc_result_t result; + dns_clientresevent_t *event; + isc_boolean_t canceled; + dns_rdataset_t *rdataset; + dns_rdataset_t *sigrdataset; +} resctx_t; + +/*% + * Argument of an internal event for synchronous name resolution. + */ +typedef struct resarg { + /* Unlocked */ + isc_appctx_t *actx; + dns_client_t *client; + isc_mutex_t lock; + + /* Locked */ + isc_result_t result; + isc_result_t vresult; + dns_namelist_t *namelist; + dns_clientrestrans_t *trans; + isc_boolean_t canceled; +} resarg_t; + +/*% + * Internal state for a single DNS request + */ +typedef struct reqctx { + /* Unlocked */ + unsigned int magic; + isc_mutex_t lock; + dns_client_t *client; + unsigned int parseoptions; + + /* Locked */ + ISC_LINK(struct reqctx) link; + isc_boolean_t canceled; + dns_tsigkey_t *tsigkey; + dns_request_t *request; + dns_clientreqevent_t *event; +} reqctx_t; + +/*% + * Argument of an internal event for synchronous DNS request. + */ +typedef struct reqarg { + /* Unlocked */ + isc_appctx_t *actx; + dns_client_t *client; + isc_mutex_t lock; + + /* Locked */ + isc_result_t result; + dns_clientreqtrans_t *trans; + isc_boolean_t canceled; +} reqarg_t; + +/*% + * Argument of an internal event for synchronous name resolution. + */ +typedef struct updatearg { + /* Unlocked */ + isc_appctx_t *actx; + dns_client_t *client; + isc_mutex_t lock; + + /* Locked */ + isc_result_t result; + dns_clientupdatetrans_t *trans; + isc_boolean_t canceled; +} updatearg_t; + +/*% + * Internal state for a single dynamic update procedure + */ +typedef struct updatectx { + /* Unlocked */ + unsigned int magic; + isc_mutex_t lock; + dns_client_t *client; + + /* Locked */ + dns_request_t *updatereq; + dns_request_t *soareq; + dns_clientrestrans_t *restrans; + dns_clientrestrans_t *restrans2; + isc_boolean_t canceled; + + /* Task Locked */ + ISC_LINK(struct updatectx) link; + dns_clientupdatestate_t state; + dns_rdataclass_t rdclass; + dns_view_t *view; + dns_message_t *updatemsg; + dns_message_t *soaquery; + dns_clientupdateevent_t *event; + dns_tsigkey_t *tsigkey; + dst_key_t *sig0key; + dns_name_t *firstname; + dns_name_t soaqname; + dns_fixedname_t zonefname; + dns_name_t *zonename; + isc_sockaddrlist_t servers; + unsigned int nservers; + isc_sockaddr_t *currentserver; + struct updatectx *bp4; + struct updatectx *bp6; +} updatectx_t; + +static isc_result_t request_soa(updatectx_t *uctx); +static void client_resfind(resctx_t *rctx, dns_fetchevent_t *event); +static isc_result_t send_update(updatectx_t *uctx); + +static isc_result_t +getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, + isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, + isc_boolean_t is_shared, dns_dispatch_t **dispp) +{ + unsigned int attrs, attrmask; + isc_sockaddr_t sa; + dns_dispatch_t *disp; + unsigned buffersize, maxbuffers, maxrequests, buckets, increment; + isc_result_t result; + + attrs = 0; + attrs |= DNS_DISPATCHATTR_UDP; + switch (family) { + case AF_INET: + attrs |= DNS_DISPATCHATTR_IPV4; + break; + case AF_INET6: + attrs |= DNS_DISPATCHATTR_IPV6; + break; + default: + INSIST(0); + } + attrmask = 0; + attrmask |= DNS_DISPATCHATTR_UDP; + attrmask |= DNS_DISPATCHATTR_TCP; + attrmask |= DNS_DISPATCHATTR_IPV4; + attrmask |= DNS_DISPATCHATTR_IPV6; + + isc_sockaddr_anyofpf(&sa, family); + + buffersize = 4096; + maxbuffers = is_shared ? 1000 : 8; + maxrequests = 32768; + buckets = is_shared ? 16411 : 3; + increment = is_shared ? 16433 : 5; + + disp = NULL; + result = dns_dispatch_getudp(dispatchmgr, socketmgr, + taskmgr, &sa, + buffersize, maxbuffers, maxrequests, + buckets, increment, + attrs, attrmask, &disp); + if (result == ISC_R_SUCCESS) + *dispp = disp; + + return (result); +} + +static isc_result_t +dns_client_createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, + unsigned int options, isc_taskmgr_t *taskmgr, + unsigned int ntasks, isc_socketmgr_t *socketmgr, + isc_timermgr_t *timermgr, dns_dispatchmgr_t *dispatchmgr, + dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, + dns_view_t **viewp) +{ + isc_result_t result; + dns_view_t *view = NULL; + const char *dbtype; + + result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view); + if (result != ISC_R_SUCCESS) + return (result); + + /* Initialize view security roots */ + result = dns_view_initsecroots(view, mctx); + if (result != ISC_R_SUCCESS) { + dns_view_detach(&view); + return (result); + } + + result = dns_view_createresolver(view, taskmgr, ntasks, socketmgr, + timermgr, 0, dispatchmgr, + dispatchv4, dispatchv6); + if (result != ISC_R_SUCCESS) { + dns_view_detach(&view); + return (result); + } + + /* + * Set cache DB. + * XXX: it may be better if specific DB implementations can be + * specified via some configuration knob. + */ + if ((options & DNS_CLIENTCREATEOPT_USECACHE) != 0) + dbtype = "rbt"; + else + dbtype = "ecdb"; + result = dns_db_create(mctx, dbtype, dns_rootname, dns_dbtype_cache, + rdclass, 0, NULL, &view->cachedb); + if (result != ISC_R_SUCCESS) { + dns_view_detach(&view); + return (result); + } + + *viewp = view; + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_client_create(dns_client_t **clientp, unsigned int options) { + isc_result_t result; + isc_mem_t *mctx = NULL; + isc_appctx_t *actx = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_socketmgr_t *socketmgr = NULL; + isc_timermgr_t *timermgr = NULL; + + result = isc_mem_create(0, 0, &mctx); + if (result != ISC_R_SUCCESS) + return (result); + result = isc_appctx_create(mctx, &actx); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = isc_app_ctxstart(actx); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = isc_socketmgr_createinctx(mctx, actx, &socketmgr); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = isc_timermgr_createinctx(mctx, actx, &timermgr); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr, + options, clientp); + if (result != ISC_R_SUCCESS) + goto cleanup; + + (*clientp)->attributes |= DNS_CLIENTATTR_OWNCTX; + + /* client has its own reference to mctx, so we can detach it here */ + isc_mem_detach(&mctx); + + return (ISC_R_SUCCESS); + + cleanup: + if (taskmgr != NULL) + isc_taskmgr_destroy(&taskmgr); + if (timermgr != NULL) + isc_timermgr_destroy(&timermgr); + if (socketmgr != NULL) + isc_socketmgr_destroy(&socketmgr); + if (actx != NULL) + isc_appctx_destroy(&actx); + isc_mem_detach(&mctx); + + return (result); +} + +isc_result_t +dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, + isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, + unsigned int options, dns_client_t **clientp) +{ + dns_client_t *client; + isc_result_t result; + dns_dispatchmgr_t *dispatchmgr = NULL; + dns_dispatch_t *dispatchv4 = NULL; + dns_dispatch_t *dispatchv6 = NULL; + dns_view_t *view = NULL; + + REQUIRE(mctx != NULL); + REQUIRE(taskmgr != NULL); + REQUIRE(timermgr != NULL); + REQUIRE(socketmgr != NULL); + REQUIRE(clientp != NULL && *clientp == NULL); + + client = isc_mem_get(mctx, sizeof(*client)); + if (client == NULL) + return (ISC_R_NOMEMORY); + + result = isc_mutex_init(&client->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, client, sizeof(*client)); + return (result); + } + + client->actx = actx; + client->taskmgr = taskmgr; + client->socketmgr = socketmgr; + client->timermgr = timermgr; + + client->task = NULL; + result = isc_task_create(client->taskmgr, 0, &client->task); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr); + if (result != ISC_R_SUCCESS) + goto cleanup; + client->dispatchmgr = dispatchmgr; + + /* TODO: whether to use dispatch v4 or v6 should be configurable */ + client->dispatchv4 = NULL; + client->dispatchv6 = NULL; + result = getudpdispatch(AF_INET, dispatchmgr, socketmgr, + taskmgr, ISC_TRUE, &dispatchv4); + if (result == ISC_R_SUCCESS) + client->dispatchv4 = dispatchv4; + result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr, + taskmgr, ISC_TRUE, &dispatchv6); + if (result == ISC_R_SUCCESS) + client->dispatchv6 = dispatchv6; + + /* We need at least one of the dispatchers */ + if (dispatchv4 == NULL && dispatchv6 == NULL) { + INSIST(result != ISC_R_SUCCESS); + goto cleanup; + } + + /* Create the default view for class IN */ + result = dns_client_createview(mctx, dns_rdataclass_in, options, + taskmgr, 31, socketmgr, timermgr, + dispatchmgr, dispatchv4, dispatchv6, + &view); + if (result != ISC_R_SUCCESS) + goto cleanup; + ISC_LIST_INIT(client->viewlist); + ISC_LIST_APPEND(client->viewlist, view, link); + + dns_view_freeze(view); /* too early? */ + + ISC_LIST_INIT(client->resctxs); + ISC_LIST_INIT(client->reqctxs); + ISC_LIST_INIT(client->updatectxs); + + client->mctx = NULL; + isc_mem_attach(mctx, &client->mctx); + + client->update_timeout = DEF_UPDATE_TIMEOUT; + client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT; + client->update_udpretries = DEF_UPDATE_UDPRETRIES; + client->find_timeout = DEF_FIND_TIMEOUT; + client->find_udpretries = DEF_FIND_UDPRETRIES; + + client->references = 1; + client->magic = DNS_CLIENT_MAGIC; + + *clientp = client; + + return (ISC_R_SUCCESS); + + cleanup: + if (dispatchv4 != NULL) + dns_dispatch_detach(&dispatchv4); + if (dispatchv6 != NULL) + dns_dispatch_detach(&dispatchv6); + if (dispatchmgr != NULL) + dns_dispatchmgr_destroy(&dispatchmgr); + if (client->task != NULL) + isc_task_detach(&client->task); + isc_mem_put(mctx, client, sizeof(*client)); + + return (result); +} + +static void +destroyclient(dns_client_t **clientp) { + dns_client_t *client = *clientp; + dns_view_t *view; + + while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) { + ISC_LIST_UNLINK(client->viewlist, view, link); + dns_view_detach(&view); + } + + if (client->dispatchv4 != NULL) + dns_dispatch_detach(&client->dispatchv4); + if (client->dispatchv6 != NULL) + dns_dispatch_detach(&client->dispatchv6); + + dns_dispatchmgr_destroy(&client->dispatchmgr); + + isc_task_detach(&client->task); + + /* + * If the client has created its own running environments, + * destroy them. + */ + if ((client->attributes & DNS_CLIENTATTR_OWNCTX) != 0) { + isc_taskmgr_destroy(&client->taskmgr); + isc_timermgr_destroy(&client->timermgr); + isc_socketmgr_destroy(&client->socketmgr); + + isc_app_ctxfinish(client->actx); + isc_appctx_destroy(&client->actx); + } + + DESTROYLOCK(&client->lock); + client->magic = 0; + + isc_mem_putanddetach(&client->mctx, client, sizeof(*client)); + + *clientp = NULL; +} + +void +dns_client_destroy(dns_client_t **clientp) { + dns_client_t *client; + isc_boolean_t destroyok = ISC_FALSE; + + REQUIRE(clientp != NULL); + client = *clientp; + REQUIRE(DNS_CLIENT_VALID(client)); + + LOCK(&client->lock); + client->references--; + if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) && + ISC_LIST_EMPTY(client->reqctxs) && + ISC_LIST_EMPTY(client->updatectxs)) { + destroyok = ISC_TRUE; + } + UNLOCK(&client->lock); + + if (destroyok) + destroyclient(&client); + + *clientp = NULL; +} + +isc_result_t +dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass, + dns_name_t *namespace, isc_sockaddrlist_t *addrs) +{ + isc_result_t result; + dns_view_t *view = NULL; + + REQUIRE(DNS_CLIENT_VALID(client)); + REQUIRE(addrs != NULL); + + if (namespace == NULL) + namespace = dns_rootname; + + LOCK(&client->lock); + result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, + rdclass, &view); + if (result != ISC_R_SUCCESS) { + UNLOCK(&client->lock); + return (result); + } + UNLOCK(&client->lock); + + result = dns_fwdtable_add(view->fwdtable, namespace, addrs, + dns_fwdpolicy_only); + + dns_view_detach(&view); + + return (result); +} + +isc_result_t +dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass, + dns_name_t *namespace) +{ + isc_result_t result; + dns_view_t *view = NULL; + + REQUIRE(DNS_CLIENT_VALID(client)); + + if (namespace == NULL) + namespace = dns_rootname; + + LOCK(&client->lock); + result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, + rdclass, &view); + if (result != ISC_R_SUCCESS) { + UNLOCK(&client->lock); + return (result); + } + UNLOCK(&client->lock); + + result = dns_fwdtable_delete(view->fwdtable, namespace); + + dns_view_detach(&view); + + return (result); +} + +static isc_result_t +getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) { + dns_rdataset_t *rdataset; + + REQUIRE(mctx != NULL); + REQUIRE(rdatasetp != NULL && *rdatasetp == NULL); + + rdataset = isc_mem_get(mctx, sizeof(*rdataset)); + if (rdataset == NULL) + return (ISC_R_NOMEMORY); + + dns_rdataset_init(rdataset); + + *rdatasetp = rdataset; + + return (ISC_R_SUCCESS); +} + +static void +putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) { + dns_rdataset_t *rdataset; + + REQUIRE(rdatasetp != NULL); + rdataset = *rdatasetp; + REQUIRE(rdataset != NULL); + + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + + isc_mem_put(mctx, rdataset, sizeof(*rdataset)); + + *rdatasetp = NULL; +} + +static void +fetch_done(isc_task_t *task, isc_event_t *event) { + resctx_t *rctx = event->ev_arg; + dns_fetchevent_t *fevent; + + REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE); + REQUIRE(RCTX_VALID(rctx)); + REQUIRE(rctx->task == task); + fevent = (dns_fetchevent_t *)event; + + client_resfind(rctx, fevent); +} + +static inline isc_result_t +start_fetch(resctx_t *rctx) { + isc_result_t result; + + /* + * The caller must be holding the rctx's lock. + */ + + REQUIRE(rctx->fetch == NULL); + + result = dns_resolver_createfetch(rctx->view->resolver, + dns_fixedname_name(&rctx->name), + rctx->type, + NULL, NULL, NULL, 0, + rctx->task, fetch_done, rctx, + rctx->rdataset, + rctx->sigrdataset, + &rctx->fetch); + + return (result); +} + +static isc_result_t +view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep, + dns_name_t *foundname) +{ + isc_result_t result; + dns_name_t *name = dns_fixedname_name(&rctx->name); + dns_rdatatype_t type; + + if (rctx->type == dns_rdatatype_rrsig) + type = dns_rdatatype_any; + else + type = rctx->type; + + result = dns_view_find(rctx->view, name, type, 0, 0, ISC_FALSE, + dbp, nodep, foundname, rctx->rdataset, + rctx->sigrdataset); + + return (result); +} + +static void +client_resfind(resctx_t *rctx, dns_fetchevent_t *event) { + isc_mem_t *mctx; + isc_result_t result, tresult; + isc_result_t vresult = ISC_R_SUCCESS; + isc_boolean_t want_restart; + isc_boolean_t send_event = ISC_FALSE; + dns_name_t *name, *prefix; + dns_fixedname_t foundname, fixed; + dns_rdataset_t *trdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned int nlabels; + int order; + dns_namereln_t namereln; + dns_rdata_cname_t cname; + dns_rdata_dname_t dname; + + REQUIRE(RCTX_VALID(rctx)); + + LOCK(&rctx->lock); + + mctx = rctx->view->mctx; + + result = ISC_R_SUCCESS; + name = dns_fixedname_name(&rctx->name); + + do { + dns_name_t *fname = NULL; + dns_name_t *ansname = NULL; + dns_db_t *db = NULL; + dns_dbnode_t *node = NULL; + + rctx->restarts++; + want_restart = ISC_FALSE; + + if (event == NULL && !rctx->canceled) { + dns_fixedname_init(&foundname); + fname = dns_fixedname_name(&foundname); + INSIST(!dns_rdataset_isassociated(rctx->rdataset)); + INSIST(rctx->sigrdataset == NULL || + !dns_rdataset_isassociated(rctx->sigrdataset)); + result = view_find(rctx, &db, &node, fname); + if (result == ISC_R_NOTFOUND) { + /* + * We don't know anything about the name. + * Launch a fetch. + */ + if (node != NULL) { + INSIST(db != NULL); + dns_db_detachnode(db, &node); + } + if (db != NULL) + dns_db_detach(&db); + result = start_fetch(rctx); + if (result != ISC_R_SUCCESS) { + putrdataset(mctx, &rctx->rdataset); + if (rctx->sigrdataset != NULL) + putrdataset(mctx, + &rctx->sigrdataset); + send_event = ISC_TRUE; + } + goto done; + } + } else { + INSIST(event->fetch == rctx->fetch); + dns_resolver_destroyfetch(&rctx->fetch); + db = event->db; + node = event->node; + result = event->result; + vresult = event->vresult; + fname = dns_fixedname_name(&event->foundname); + INSIST(event->rdataset == rctx->rdataset); + INSIST(event->sigrdataset == rctx->sigrdataset); + } + + /* + * If we've been canceled, forget about the result. + */ + if (rctx->canceled) + result = ISC_R_CANCELED; + else { + /* + * Otherwise, get some resource for copying the + * result. + */ + ansname = isc_mem_get(mctx, sizeof(*ansname)); + if (ansname == NULL) + tresult = ISC_R_NOMEMORY; + else { + dns_name_t *aname; + + aname = dns_fixedname_name(&rctx->name); + dns_name_init(ansname, NULL); + tresult = dns_name_dup(aname, mctx, ansname); + if (tresult != ISC_R_SUCCESS) + isc_mem_put(mctx, ansname, + sizeof(*ansname)); + } + if (tresult != ISC_R_SUCCESS) + result = tresult; + } + + switch (result) { + case ISC_R_SUCCESS: + send_event = ISC_TRUE; + /* + * This case is handled in the main line below. + */ + break; + case DNS_R_CNAME: + /* + * Add the CNAME to the answer list. + */ + trdataset = rctx->rdataset; + ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); + rctx->rdataset = NULL; + if (rctx->sigrdataset != NULL) { + ISC_LIST_APPEND(ansname->list, + rctx->sigrdataset, link); + rctx->sigrdataset = NULL; + } + ISC_LIST_APPEND(rctx->namelist, ansname, link); + ansname = NULL; + + /* + * Copy the CNAME's target into the lookup's + * query name and start over. + */ + tresult = dns_rdataset_first(trdataset); + if (tresult != ISC_R_SUCCESS) + goto done; + dns_rdataset_current(trdataset, &rdata); + tresult = dns_rdata_tostruct(&rdata, &cname, NULL); + dns_rdata_reset(&rdata); + if (tresult != ISC_R_SUCCESS) + goto done; + tresult = dns_name_copy(&cname.cname, name, NULL); + dns_rdata_freestruct(&cname); + if (tresult == ISC_R_SUCCESS) + want_restart = ISC_TRUE; + else + result = tresult; + goto done; + case DNS_R_DNAME: + /* + * Add the DNAME to the answer list. + */ + trdataset = rctx->rdataset; + ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); + rctx->rdataset = NULL; + if (rctx->sigrdataset != NULL) { + ISC_LIST_APPEND(ansname->list, + rctx->sigrdataset, link); + rctx->sigrdataset = NULL; + } + ISC_LIST_APPEND(rctx->namelist, ansname, link); + ansname = NULL; + + namereln = dns_name_fullcompare(name, fname, &order, + &nlabels); + INSIST(namereln == dns_namereln_subdomain); + /* + * Get the target name of the DNAME. + */ + tresult = dns_rdataset_first(trdataset); + if (tresult != ISC_R_SUCCESS) { + result = tresult; + goto done; + } + dns_rdataset_current(trdataset, &rdata); + tresult = dns_rdata_tostruct(&rdata, &dname, NULL); + dns_rdata_reset(&rdata); + if (tresult != ISC_R_SUCCESS) { + result = tresult; + goto done; + } + /* + * Construct the new query name and start over. + */ + dns_fixedname_init(&fixed); + prefix = dns_fixedname_name(&fixed); + dns_name_split(name, nlabels, prefix, NULL); + tresult = dns_name_concatenate(prefix, &dname.dname, + name, NULL); + dns_rdata_freestruct(&dname); + if (tresult == ISC_R_SUCCESS) + want_restart = ISC_TRUE; + else + result = tresult; + goto done; + case DNS_R_NCACHENXDOMAIN: + case DNS_R_NCACHENXRRSET: + ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); + ISC_LIST_APPEND(rctx->namelist, ansname, link); + ansname = NULL; + rctx->rdataset = NULL; + /* What about sigrdataset? */ + if (rctx->sigrdataset != NULL) + putrdataset(mctx, &rctx->sigrdataset); + send_event = ISC_TRUE; + goto done; + default: + if (rctx->rdataset != NULL) + putrdataset(mctx, &rctx->rdataset); + if (rctx->sigrdataset != NULL) + putrdataset(mctx, &rctx->sigrdataset); + send_event = ISC_TRUE; + goto done; + } + + if (rctx->type == dns_rdatatype_any) { + int n = 0; + dns_rdatasetiter_t *rdsiter = NULL; + + tresult = dns_db_allrdatasets(db, node, NULL, 0, + &rdsiter); + if (tresult != ISC_R_SUCCESS) { + result = tresult; + goto done; + } + + tresult = dns_rdatasetiter_first(rdsiter); + while (tresult == ISC_R_SUCCESS) { + dns_rdatasetiter_current(rdsiter, + rctx->rdataset); + if (rctx->rdataset->type != 0) { + ISC_LIST_APPEND(ansname->list, + rctx->rdataset, + link); + n++; + rctx->rdataset = NULL; + } else { + /* + * We're not interested in this + * rdataset. + */ + dns_rdataset_disassociate( + rctx->rdataset); + } + tresult = dns_rdatasetiter_next(rdsiter); + + if (tresult == ISC_R_SUCCESS && + rctx->rdataset == NULL) { + tresult = getrdataset(mctx, + &rctx->rdataset); + if (tresult != ISC_R_SUCCESS) { + result = tresult; + break; + } + } + } + if (n == 0) { + /* + * We didn't match any rdatasets (which means + * something went wrong in this + * implementation). + */ + result = DNS_R_SERVFAIL; /* better code? */ + } else { + ISC_LIST_APPEND(rctx->namelist, ansname, link); + ansname = NULL; + } + dns_rdatasetiter_destroy(&rdsiter); + if (tresult != ISC_R_NOMORE) + result = DNS_R_SERVFAIL; /* ditto */ + else + result = ISC_R_SUCCESS; + goto done; + } else { + /* + * This is the "normal" case -- an ordinary question + * to which we've got the answer. + */ + ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); + rctx->rdataset = NULL; + if (rctx->sigrdataset != NULL) { + ISC_LIST_APPEND(ansname->list, + rctx->sigrdataset, link); + rctx->sigrdataset = NULL; + } + ISC_LIST_APPEND(rctx->namelist, ansname, link); + ansname = NULL; + } + + done: + /* + * Free temporary resources + */ + if (ansname != NULL) { + dns_rdataset_t *rdataset; + + while ((rdataset = ISC_LIST_HEAD(ansname->list)) + != NULL) { + ISC_LIST_UNLINK(ansname->list, rdataset, link); + putrdataset(mctx, &rdataset); + } + dns_name_free(ansname, mctx); + isc_mem_put(mctx, ansname, sizeof(*ansname)); + } + + if (node != NULL) + dns_db_detachnode(db, &node); + if (db != NULL) + dns_db_detach(&db); + if (event != NULL) + isc_event_free(ISC_EVENT_PTR(&event)); + + /* + * Limit the number of restarts. + */ + if (want_restart && rctx->restarts == MAX_RESTARTS) { + want_restart = ISC_FALSE; + result = ISC_R_QUOTA; + send_event = ISC_TRUE; + } + + /* + * Prepare further find with new resources + */ + if (want_restart) { + INSIST(rctx->rdataset == NULL && + rctx->sigrdataset == NULL); + + result = getrdataset(mctx, &rctx->rdataset); + if (result == ISC_R_SUCCESS && rctx->want_dnssec) { + result = getrdataset(mctx, &rctx->sigrdataset); + if (result != ISC_R_SUCCESS) { + putrdataset(mctx, &rctx->rdataset); + } + } + + if (result != ISC_R_SUCCESS) { + want_restart = ISC_FALSE; + send_event = ISC_TRUE; + } + } + } while (want_restart); + + if (send_event) { + isc_task_t *task; + + while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) { + ISC_LIST_UNLINK(rctx->namelist, name, link); + ISC_LIST_APPEND(rctx->event->answerlist, name, link); + } + + rctx->event->result = result; + rctx->event->vresult = vresult; + task = rctx->event->ev_sender; + rctx->event->ev_sender = rctx; + isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event)); + } + + UNLOCK(&rctx->lock); +} + +static void +resolve_done(isc_task_t *task, isc_event_t *event) { + resarg_t *resarg = event->ev_arg; + dns_clientresevent_t *rev = (dns_clientresevent_t *)event; + dns_name_t *name; + + UNUSED(task); + + LOCK(&resarg->lock); + + resarg->result = rev->result; + resarg->vresult = rev->vresult; + while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) { + ISC_LIST_UNLINK(rev->answerlist, name, link); + ISC_LIST_APPEND(*resarg->namelist, name, link); + } + + dns_client_destroyrestrans(&resarg->trans); + isc_event_free(&event); + + if (!resarg->canceled) { + UNLOCK(&resarg->lock); + + /* Exit from the internal event loop */ + isc_app_ctxsuspend(resarg->actx); + } else { + /* + * We have already exited from the loop (due to some + * unexpected event). Just clean the arg up. + */ + UNLOCK(&resarg->lock); + DESTROYLOCK(&resarg->lock); + isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg)); + } +} + +isc_result_t +dns_client_resolve(dns_client_t *client, dns_name_t *name, + dns_rdataclass_t rdclass, dns_rdatatype_t type, + unsigned int options, dns_namelist_t *namelist) +{ + isc_result_t result; + isc_appctx_t *actx; + resarg_t *resarg; + + REQUIRE(DNS_CLIENT_VALID(client)); + REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist)); + + if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 && + (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) { + /* + * If the client is run under application's control, we need + * to create a new running (sub)environment for this + * particular resolution. + */ + return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */ + } else + actx = client->actx; + + resarg = isc_mem_get(client->mctx, sizeof(*resarg)); + if (resarg == NULL) + return (ISC_R_NOMEMORY); + + result = isc_mutex_init(&resarg->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(client->mctx, resarg, sizeof(*resarg)); + return (result); + } + + resarg->actx = actx; + resarg->client = client; + resarg->result = DNS_R_SERVFAIL; + resarg->namelist = namelist; + resarg->trans = NULL; + resarg->canceled = ISC_FALSE; + result = dns_client_startresolve(client, name, rdclass, type, options, + client->task, resolve_done, resarg, + &resarg->trans); + if (result != ISC_R_SUCCESS) { + DESTROYLOCK(&resarg->lock); + isc_mem_put(client->mctx, resarg, sizeof(*resarg)); + return (result); + } + + /* + * Start internal event loop. It blocks until the entire process + * is completed. + */ + result = isc_app_ctxrun(actx); + + LOCK(&resarg->lock); + if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) + result = resarg->result; + if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) { + /* + * If this lookup failed due to some error in DNSSEC + * validation, return the validation error code. + * XXX: or should we pass the validation result separately? + */ + result = resarg->vresult; + } + if (resarg->trans != NULL) { + /* + * Unusual termination (perhaps due to signal). We need some + * tricky cleanup process. + */ + resarg->canceled = ISC_TRUE; + dns_client_cancelresolve(resarg->trans); + + UNLOCK(&resarg->lock); + + /* resarg will be freed in the event handler. */ + } else { + UNLOCK(&resarg->lock); + + DESTROYLOCK(&resarg->lock); + isc_mem_put(client->mctx, resarg, sizeof(*resarg)); + } + + return (result); +} + +isc_result_t +dns_client_startresolve(dns_client_t *client, dns_name_t *name, + dns_rdataclass_t rdclass, dns_rdatatype_t type, + unsigned int options, isc_task_t *task, + isc_taskaction_t action, void *arg, + dns_clientrestrans_t **transp) +{ + dns_view_t *view = NULL; + dns_clientresevent_t *event = NULL; + resctx_t *rctx = NULL; + isc_task_t *clone = NULL; + isc_mem_t *mctx; + isc_result_t result; + dns_rdataset_t *rdataset, *sigrdataset; + isc_boolean_t want_dnssec; + + REQUIRE(DNS_CLIENT_VALID(client)); + REQUIRE(transp != NULL && *transp == NULL); + + LOCK(&client->lock); + result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, + rdclass, &view); + UNLOCK(&client->lock); + if (result != ISC_R_SUCCESS) + return (result); + + mctx = client->mctx; + rdataset = NULL; + sigrdataset = NULL; + want_dnssec = ISC_TF((options & DNS_CLIENTRESOPT_NODNSSEC) == 0); + + /* + * Prepare some intermediate resources + */ + clone = NULL; + isc_task_attach(task, &clone); + event = (dns_clientresevent_t *) + isc_event_allocate(mctx, clone, DNS_EVENT_CLIENTRESDONE, + action, arg, sizeof(*event)); + if (event == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + event->result = DNS_R_SERVFAIL; + ISC_LIST_INIT(event->answerlist); + + rctx = isc_mem_get(mctx, sizeof(*rctx)); + if (rctx == NULL) + result = ISC_R_NOMEMORY; + else { + result = isc_mutex_init(&rctx->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, rctx, sizeof(*rctx)); + rctx = NULL; + } + } + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = getrdataset(mctx, &rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + rctx->rdataset = rdataset; + + if (want_dnssec) { + result = getrdataset(mctx, &sigrdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + rctx->sigrdataset = sigrdataset; + + dns_fixedname_init(&rctx->name); + result = dns_name_copy(name, dns_fixedname_name(&rctx->name), NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + + rctx->client = client; + ISC_LINK_INIT(rctx, link); + rctx->canceled = ISC_FALSE; + rctx->task = client->task; + rctx->type = type; + rctx->view = view; + rctx->restarts = 0; + rctx->fetch = NULL; + rctx->want_dnssec = want_dnssec; + ISC_LIST_INIT(rctx->namelist); + rctx->event = event; + + rctx->magic = RCTX_MAGIC; + + LOCK(&client->lock); + ISC_LIST_APPEND(client->resctxs, rctx, link); + UNLOCK(&client->lock); + + client_resfind(rctx, NULL); + + *transp = (dns_clientrestrans_t *)rctx; + + return (ISC_R_SUCCESS); + + cleanup: + if (rdataset != NULL) + putrdataset(client->mctx, &rdataset); + if (sigrdataset != NULL) + putrdataset(client->mctx, &sigrdataset); + if (rctx != NULL) { + DESTROYLOCK(&rctx->lock); + isc_mem_put(mctx, rctx, sizeof(*rctx)); + } + if (event != NULL) + isc_event_free(ISC_EVENT_PTR(&event)); + isc_task_detach(&clone); + dns_view_detach(&view); + + return (result); +} + +void +dns_client_cancelresolve(dns_clientrestrans_t *trans) { + resctx_t *rctx; + + REQUIRE(trans != NULL); + rctx = (resctx_t *)trans; + REQUIRE(RCTX_VALID(rctx)); + + LOCK(&rctx->lock); + + if (!rctx->canceled) { + rctx->canceled = ISC_TRUE; + if (rctx->fetch != NULL) + dns_resolver_cancelfetch(rctx->fetch); + } + + UNLOCK(&rctx->lock); +} + +void +dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) { + dns_name_t *name; + dns_rdataset_t *rdataset; + + REQUIRE(DNS_CLIENT_VALID(client)); + REQUIRE(namelist != NULL); + + while ((name = ISC_LIST_HEAD(*namelist)) != NULL) { + ISC_LIST_UNLINK(*namelist, name, link); + while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) { + ISC_LIST_UNLINK(name->list, rdataset, link); + putrdataset(client->mctx, &rdataset); + } + dns_name_free(name, client->mctx); + isc_mem_put(client->mctx, name, sizeof(*name)); + } +} + +void +dns_client_destroyrestrans(dns_clientrestrans_t **transp) { + resctx_t *rctx; + isc_mem_t *mctx; + dns_client_t *client; + isc_boolean_t need_destroyclient = ISC_FALSE; + + REQUIRE(transp != NULL); + rctx = (resctx_t *)*transp; + REQUIRE(RCTX_VALID(rctx)); + REQUIRE(rctx->fetch == NULL); + REQUIRE(rctx->event == NULL); + client = rctx->client; + REQUIRE(DNS_CLIENT_VALID(client)); + + mctx = client->mctx; + dns_view_detach(&rctx->view); + + LOCK(&client->lock); + + INSIST(ISC_LINK_LINKED(rctx, link)); + ISC_LIST_UNLINK(client->resctxs, rctx, link); + + if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) && + ISC_LIST_EMPTY(client->reqctxs) && + ISC_LIST_EMPTY(client->updatectxs)) + need_destroyclient = ISC_TRUE; + + UNLOCK(&client->lock); + + INSIST(ISC_LIST_EMPTY(rctx->namelist)); + + DESTROYLOCK(&rctx->lock); + rctx->magic = 0; + + isc_mem_put(mctx, rctx, sizeof(*rctx)); + + if (need_destroyclient) + destroyclient(&client); + + *transp = NULL; +} + +isc_result_t +dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass, + dns_name_t *keyname, isc_buffer_t *keydatabuf) +{ + isc_result_t result; + dns_view_t *view = NULL; + dst_key_t *dstkey = NULL; + dns_keytable_t *secroots = NULL; + + REQUIRE(DNS_CLIENT_VALID(client)); + + LOCK(&client->lock); + result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, + rdclass, &view); + UNLOCK(&client->lock); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dns_view_getsecroots(view, &secroots); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dst_key_fromdns(keyname, rdclass, keydatabuf, client->mctx, + &dstkey); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dns_keytable_add(secroots, ISC_FALSE, &dstkey); + + cleanup: + if (dstkey != NULL) + dst_key_free(&dstkey); + if (view != NULL) + dns_view_detach(&view); + if (secroots != NULL) + dns_keytable_detach(&secroots); + return (result); +} + +/*% + * Simple request routines + */ +static void +request_done(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *reqev = NULL; + dns_request_t *request; + isc_result_t result, eresult; + reqctx_t *ctx; + + UNUSED(task); + + REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); + reqev = (dns_requestevent_t *)event; + request = reqev->request; + result = eresult = reqev->result; + ctx = reqev->ev_arg; + REQUIRE(REQCTX_VALID(ctx)); + + isc_event_free(&event); + + LOCK(&ctx->lock); + + if (eresult == ISC_R_SUCCESS) { + result = dns_request_getresponse(request, ctx->event->rmessage, + ctx->parseoptions); + } + + if (ctx->tsigkey != NULL) + dns_tsigkey_detach(&ctx->tsigkey); + + if (ctx->canceled) + ctx->event->result = ISC_R_CANCELED; + else + ctx->event->result = result; + task = ctx->event->ev_sender; + ctx->event->ev_sender = ctx; + isc_task_sendanddetach(&task, ISC_EVENT_PTR(&ctx->event)); + + UNLOCK(&ctx->lock); +} + +static void +localrequest_done(isc_task_t *task, isc_event_t *event) { + reqarg_t *reqarg = event->ev_arg; + dns_clientreqevent_t *rev =(dns_clientreqevent_t *)event; + + UNUSED(task); + + REQUIRE(event->ev_type == DNS_EVENT_CLIENTREQDONE); + + LOCK(&reqarg->lock); + + reqarg->result = rev->result; + dns_client_destroyreqtrans(&reqarg->trans); + isc_event_free(&event); + + if (!reqarg->canceled) { + UNLOCK(&reqarg->lock); + + /* Exit from the internal event loop */ + isc_app_ctxsuspend(reqarg->actx); + } else { + /* + * We have already exited from the loop (due to some + * unexpected event). Just clean the arg up. + */ + UNLOCK(&reqarg->lock); + DESTROYLOCK(&reqarg->lock); + isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg)); + } +} + +isc_result_t +dns_client_request(dns_client_t *client, dns_message_t *qmessage, + dns_message_t *rmessage, isc_sockaddr_t *server, + unsigned int options, unsigned int parseoptions, + dns_tsec_t *tsec, unsigned int timeout, + unsigned int udptimeout, unsigned int udpretries) +{ + isc_appctx_t *actx; + reqarg_t *reqarg; + isc_result_t result; + + REQUIRE(DNS_CLIENT_VALID(client)); + REQUIRE(qmessage != NULL); + REQUIRE(rmessage != NULL); + + if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 && + (options & DNS_CLIENTREQOPT_ALLOWRUN) == 0) { + /* + * If the client is run under application's control, we need + * to create a new running (sub)environment for this + * particular resolution. + */ + return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */ + } else + actx = client->actx; + + reqarg = isc_mem_get(client->mctx, sizeof(*reqarg)); + if (reqarg == NULL) + return (ISC_R_NOMEMORY); + + result = isc_mutex_init(&reqarg->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(client->mctx, reqarg, sizeof(*reqarg)); + return (result); + } + + reqarg->actx = actx; + reqarg->client = client; + reqarg->trans = NULL; + reqarg->canceled = ISC_FALSE; + + result = dns_client_startrequest(client, qmessage, rmessage, server, + options, parseoptions, tsec, timeout, + udptimeout, udpretries, + client->task, localrequest_done, + reqarg, &reqarg->trans); + if (result != ISC_R_SUCCESS) { + DESTROYLOCK(&reqarg->lock); + isc_mem_put(client->mctx, reqarg, sizeof(*reqarg)); + return (result); + } + + /* + * Start internal event loop. It blocks until the entire process + * is completed. + */ + result = isc_app_ctxrun(actx); + + LOCK(&reqarg->lock); + if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) + result = reqarg->result; + if (reqarg->trans != NULL) { + /* + * Unusual termination (perhaps due to signal). We need some + * tricky cleanup process. + */ + reqarg->canceled = ISC_TRUE; + dns_client_cancelresolve(reqarg->trans); + + UNLOCK(&reqarg->lock); + + /* reqarg will be freed in the event handler. */ + } else { + UNLOCK(&reqarg->lock); + + DESTROYLOCK(&reqarg->lock); + isc_mem_put(client->mctx, reqarg, sizeof(*reqarg)); + } + + return (result); +} + +isc_result_t +dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage, + dns_message_t *rmessage, isc_sockaddr_t *server, + unsigned int options, unsigned int parseoptions, + dns_tsec_t *tsec, unsigned int timeout, + unsigned int udptimeout, unsigned int udpretries, + isc_task_t *task, isc_taskaction_t action, void *arg, + dns_clientreqtrans_t **transp) +{ + isc_result_t result; + dns_view_t *view = NULL; + isc_task_t *clone = NULL; + dns_clientreqevent_t *event = NULL; + reqctx_t *ctx = NULL; + dns_tsectype_t tsectype = dns_tsectype_none; + + UNUSED(options); + + REQUIRE(DNS_CLIENT_VALID(client)); + REQUIRE(qmessage != NULL); + REQUIRE(rmessage != NULL); + REQUIRE(transp != NULL && *transp == NULL); + + if (tsec != NULL) { + tsectype = dns_tsec_gettype(tsec); + if (tsectype != dns_tsectype_tsig) + return (ISC_R_NOTIMPLEMENTED); /* XXX */ + } + + LOCK(&client->lock); + result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, + qmessage->rdclass, &view); + UNLOCK(&client->lock); + if (result != ISC_R_SUCCESS) + return (result); + + clone = NULL; + isc_task_attach(task, &clone); + event = (dns_clientreqevent_t *) + isc_event_allocate(client->mctx, clone, + DNS_EVENT_CLIENTREQDONE, + action, arg, sizeof(*event)); + if (event == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + + ctx = isc_mem_get(client->mctx, sizeof(*ctx)); + if (ctx == NULL) + result = ISC_R_NOMEMORY; + else { + result = isc_mutex_init(&ctx->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(client->mctx, ctx, sizeof(*ctx)); + ctx = NULL; + } + } + if (result != ISC_R_SUCCESS) + goto cleanup; + + ctx->client = client; + ISC_LINK_INIT(ctx, link); + ctx->parseoptions = parseoptions; + ctx->canceled = ISC_FALSE; + ctx->event = event; + ctx->event->rmessage = rmessage; + ctx->tsigkey = NULL; + if (tsec != NULL) + dns_tsec_getkey(tsec, &ctx->tsigkey); + + ctx->magic = REQCTX_MAGIC; + + LOCK(&client->lock); + ISC_LIST_APPEND(client->reqctxs, ctx, link); + UNLOCK(&client->lock); + + ctx->request = NULL; + result = dns_request_createvia3(view->requestmgr, qmessage, NULL, + server, options, ctx->tsigkey, + timeout, udptimeout, udpretries, + client->task, request_done, ctx, + &ctx->request); + if (result == ISC_R_SUCCESS) { + dns_view_detach(&view); + *transp = (dns_clientreqtrans_t *)ctx; + return (ISC_R_SUCCESS); + } + + cleanup: + if (ctx != NULL) { + LOCK(&client->lock); + ISC_LIST_UNLINK(client->reqctxs, ctx, link); + UNLOCK(&client->lock); + DESTROYLOCK(&ctx->lock); + isc_mem_put(client->mctx, ctx, sizeof(*ctx)); + } + if (event != NULL) + isc_event_free(ISC_EVENT_PTR(&event)); + isc_task_detach(&clone); + dns_view_detach(&view); + + return (result); +} + +void +dns_client_cancelrequest(dns_clientreqtrans_t *trans) { + reqctx_t *ctx; + + REQUIRE(trans != NULL); + ctx = (reqctx_t *)trans; + REQUIRE(REQCTX_VALID(ctx)); + + LOCK(&ctx->lock); + + if (!ctx->canceled) { + ctx->canceled = ISC_TRUE; + if (ctx->request != NULL) + dns_request_cancel(ctx->request); + } + + UNLOCK(&ctx->lock); +} + +void +dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) { + reqctx_t *ctx; + isc_mem_t *mctx; + dns_client_t *client; + isc_boolean_t need_destroyclient = ISC_FALSE; + + REQUIRE(transp != NULL); + ctx = (reqctx_t *)*transp; + REQUIRE(REQCTX_VALID(ctx)); + client = ctx->client; + REQUIRE(DNS_CLIENT_VALID(client)); + REQUIRE(ctx->event == NULL); + REQUIRE(ctx->request != NULL); + + dns_request_destroy(&ctx->request); + mctx = client->mctx; + + LOCK(&client->lock); + + INSIST(ISC_LINK_LINKED(ctx, link)); + ISC_LIST_UNLINK(client->reqctxs, ctx, link); + + if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) && + ISC_LIST_EMPTY(client->reqctxs) && + ISC_LIST_EMPTY(client->updatectxs)) { + need_destroyclient = ISC_TRUE; + } + + UNLOCK(&client->lock); + + DESTROYLOCK(&ctx->lock); + ctx->magic = 0; + + isc_mem_put(mctx, ctx, sizeof(*ctx)); + + if (need_destroyclient) + destroyclient(&client); + + *transp = NULL; +} + +/*% + * Dynamic update routines + */ +static isc_result_t +rcode2result(dns_rcode_t rcode) { + /* XXX: isn't there a similar function? */ + switch (rcode) { + case dns_rcode_formerr: + return (DNS_R_FORMERR); + case dns_rcode_servfail: + return (DNS_R_SERVFAIL); + case dns_rcode_nxdomain: + return (DNS_R_NXDOMAIN); + case dns_rcode_notimp: + return (DNS_R_NOTIMP); + case dns_rcode_refused: + return (DNS_R_REFUSED); + case dns_rcode_yxdomain: + return (DNS_R_YXDOMAIN); + case dns_rcode_yxrrset: + return (DNS_R_YXRRSET); + case dns_rcode_nxrrset: + return (DNS_R_NXRRSET); + case dns_rcode_notauth: + return (DNS_R_NOTAUTH); + case dns_rcode_notzone: + return (DNS_R_NOTZONE); + case dns_rcode_badvers: + return (DNS_R_BADVERS); + } + + return (ISC_R_FAILURE); +} + +static void +update_sendevent(updatectx_t *uctx, isc_result_t result) { + isc_task_t *task; + + dns_message_destroy(&uctx->updatemsg); + if (uctx->tsigkey != NULL) + dns_tsigkey_detach(&uctx->tsigkey); + if (uctx->sig0key != NULL) + dst_key_free(&uctx->sig0key); + + if (uctx->canceled) + uctx->event->result = ISC_R_CANCELED; + else + uctx->event->result = result; + uctx->event->state = uctx->state; + task = uctx->event->ev_sender; + uctx->event->ev_sender = uctx; + isc_task_sendanddetach(&task, ISC_EVENT_PTR(&uctx->event)); +} + +static void +update_done(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + dns_requestevent_t *reqev = NULL; + dns_request_t *request; + dns_message_t *answer = NULL; + updatectx_t *uctx = event->ev_arg; + dns_client_t *client; + unsigned int timeout; + + UNUSED(task); + + REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); + reqev = (dns_requestevent_t *)event; + request = reqev->request; + REQUIRE(UCTX_VALID(uctx)); + client = uctx->client; + REQUIRE(DNS_CLIENT_VALID(client)); + + result = reqev->result; + if (result != ISC_R_SUCCESS) + goto out; + + result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE, + &answer); + if (result != ISC_R_SUCCESS) + goto out; + uctx->state = dns_clientupdatestate_done; + result = dns_request_getresponse(request, answer, + DNS_MESSAGEPARSE_PRESERVEORDER); + if (result == ISC_R_SUCCESS && answer->rcode != dns_rcode_noerror) + result = rcode2result(answer->rcode); + + out: + if (answer != NULL) + dns_message_destroy(&answer); + isc_event_free(&event); + + LOCK(&uctx->lock); + uctx->currentserver = ISC_LIST_NEXT(uctx->currentserver, link); + dns_request_destroy(&uctx->updatereq); + if (result != ISC_R_SUCCESS && !uctx->canceled && + uctx->currentserver != NULL) { + dns_message_renderreset(uctx->updatemsg); + dns_message_settsigkey(uctx->updatemsg, NULL); + + timeout = client->update_timeout / uctx->nservers; + if (timeout < MIN_UPDATE_TIMEOUT) + timeout = MIN_UPDATE_TIMEOUT; + result = dns_request_createvia3(uctx->view->requestmgr, + uctx->updatemsg, + NULL, + uctx->currentserver, 0, + uctx->tsigkey, + timeout, + client->update_udptimeout, + client->update_udpretries, + client->task, + update_done, uctx, + &uctx->updatereq); + UNLOCK(&uctx->lock); + + if (result == ISC_R_SUCCESS) { + /* XXX: should we keep the 'done' state here? */ + uctx->state = dns_clientupdatestate_sent; + return; + } + } else + UNLOCK(&uctx->lock); + + update_sendevent(uctx, result); +} + +static isc_result_t +send_update(updatectx_t *uctx) { + isc_result_t result; + dns_name_t *name = NULL; + dns_rdataset_t *rdataset = NULL; + dns_client_t *client = uctx->client; + unsigned int timeout; + + REQUIRE(uctx->zonename != NULL && uctx->currentserver != NULL); + + result = dns_message_gettempname(uctx->updatemsg, &name); + if (result != ISC_R_SUCCESS) + return (result); + dns_name_init(name, NULL); + dns_name_clone(uctx->zonename, name); + result = dns_message_gettemprdataset(uctx->updatemsg, &rdataset); + if (result != ISC_R_SUCCESS) { + dns_message_puttempname(uctx->updatemsg, &name); + return (result); + } + dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa); + ISC_LIST_INIT(name->list); + ISC_LIST_APPEND(name->list, rdataset, link); + dns_message_addname(uctx->updatemsg, name, DNS_SECTION_ZONE); + if (uctx->tsigkey == NULL && uctx->sig0key != NULL) { + result = dns_message_setsig0key(uctx->updatemsg, + uctx->sig0key); + if (result != ISC_R_SUCCESS) + return (result); + } + timeout = client->update_timeout / uctx->nservers; + if (timeout < MIN_UPDATE_TIMEOUT) + timeout = MIN_UPDATE_TIMEOUT; + result = dns_request_createvia3(uctx->view->requestmgr, + uctx->updatemsg, + NULL, uctx->currentserver, 0, + uctx->tsigkey, timeout, + client->update_udptimeout, + client->update_udpretries, + client->task, update_done, uctx, + &uctx->updatereq); + if (result == ISC_R_SUCCESS && + uctx->state == dns_clientupdatestate_prepare) { + uctx->state = dns_clientupdatestate_sent; + } + + return (result); +} + +static void +resolveaddr_done(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + int family; + dns_rdatatype_t qtype; + dns_clientresevent_t *rev = (dns_clientresevent_t *)event; + dns_name_t *name; + dns_rdataset_t *rdataset; + updatectx_t *uctx; + isc_boolean_t completed = ISC_FALSE; + + UNUSED(task); + + REQUIRE(event->ev_arg != NULL); + uctx = *(updatectx_t **)event->ev_arg; + REQUIRE(UCTX_VALID(uctx)); + + if (event->ev_arg == &uctx->bp4) { + family = AF_INET; + qtype = dns_rdatatype_a; + LOCK(&uctx->lock); + dns_client_destroyrestrans(&uctx->restrans); + UNLOCK(&uctx->lock); + } else { + INSIST(event->ev_arg == &uctx->bp6); + family = AF_INET6; + qtype = dns_rdatatype_aaaa; + LOCK(&uctx->lock); + dns_client_destroyrestrans(&uctx->restrans2); + UNLOCK(&uctx->lock); + } + + result = rev->result; + if (result != ISC_R_SUCCESS) + goto done; + + for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; + name = ISC_LIST_NEXT(name, link)) { + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + if (!dns_rdataset_isassociated(rdataset)) + continue; + if (rdataset->type != qtype) + continue; + + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + dns_rdata_t rdata; + dns_rdata_in_a_t rdata_a; + dns_rdata_in_aaaa_t rdata_aaaa; + isc_sockaddr_t *sa; + + sa = isc_mem_get(uctx->client->mctx, + sizeof(*sa)); + if (sa == NULL) { + /* + * If we fail to get a sockaddr, + we simply move forward with the + * addresses we've got so far. + */ + goto done; + } + + dns_rdata_init(&rdata); + switch (family) { + case AF_INET: + dns_rdataset_current(rdataset, &rdata); + dns_rdata_tostruct(&rdata, &rdata_a, + NULL); + isc_sockaddr_fromin(sa, + &rdata_a.in_addr, + 53); + dns_rdata_freestruct(&rdata_a); + break; + case AF_INET6: + dns_rdataset_current(rdataset, &rdata); + dns_rdata_tostruct(&rdata, &rdata_aaaa, + NULL); + isc_sockaddr_fromin6(sa, + &rdata_aaaa.in6_addr, + 53); + dns_rdata_freestruct(&rdata_aaaa); + break; + } + + ISC_LINK_INIT(sa, link); + ISC_LIST_APPEND(uctx->servers, sa, link); + uctx->nservers++; + } + } + } + + done: + dns_client_freeresanswer(uctx->client, &rev->answerlist); + isc_event_free(&event); + + LOCK(&uctx->lock); + if (uctx->restrans == NULL && uctx->restrans2 == NULL) + completed = ISC_TRUE; + UNLOCK(&uctx->lock); + + if (completed) { + INSIST(uctx->currentserver == NULL); + uctx->currentserver = ISC_LIST_HEAD(uctx->servers); + if (uctx->currentserver != NULL && !uctx->canceled) + send_update(uctx); + else { + if (result == ISC_R_SUCCESS) + result = ISC_R_NOTFOUND; + update_sendevent(uctx, result); + } + } +} + +static isc_result_t +process_soa(updatectx_t *uctx, dns_rdataset_t *soaset, dns_name_t *soaname) { + isc_result_t result; + dns_rdata_t soarr = DNS_RDATA_INIT; + dns_rdata_soa_t soa; + dns_name_t primary; + + result = dns_rdataset_first(soaset); + if (result != ISC_R_SUCCESS) + return (result); + dns_rdata_init(&soarr); + dns_rdataset_current(soaset, &soarr); + result = dns_rdata_tostruct(&soarr, &soa, NULL); + if (result != ISC_R_SUCCESS) + return (result); + + dns_name_init(&primary, NULL); + dns_name_clone(&soa.origin, &primary); + + if (uctx->zonename == NULL) { + uctx->zonename = dns_fixedname_name(&uctx->zonefname); + result = dns_name_copy(soaname, uctx->zonename, NULL); + if (result != ISC_R_SUCCESS) + goto out; + } + + if (uctx->currentserver != NULL) + result = send_update(uctx); + else { + /* + * Get addresses of the primary server. We don't use the ADB + * feature so that we could avoid caching data. + */ + LOCK(&uctx->lock); + uctx->bp4 = uctx; + result = dns_client_startresolve(uctx->client, &primary, + uctx->rdclass, + dns_rdatatype_a, + 0, uctx->client->task, + resolveaddr_done, &uctx->bp4, + &uctx->restrans); + if (result == ISC_R_SUCCESS) { + uctx->bp6 = uctx; + result = dns_client_startresolve(uctx->client, + &primary, + uctx->rdclass, + dns_rdatatype_aaaa, + 0, uctx->client->task, + resolveaddr_done, + &uctx->bp6, + &uctx->restrans2); + } + UNLOCK(&uctx->lock); + } + + out: + dns_rdata_freestruct(&soa); + + return (result); +} + +static void +receive_soa(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *reqev = NULL; + updatectx_t *uctx; + dns_client_t *client; + isc_result_t result, eresult; + dns_request_t *request; + dns_message_t *rcvmsg = NULL; + dns_section_t section; + dns_rdataset_t *soaset = NULL; + int pass = 0; + dns_name_t *name; + dns_message_t *soaquery = NULL; + isc_sockaddr_t *addr; + isc_boolean_t seencname = ISC_FALSE; + isc_boolean_t droplabel = ISC_FALSE; + dns_name_t tname; + unsigned int nlabels; + + UNUSED(task); + + REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); + reqev = (dns_requestevent_t *)event; + request = reqev->request; + result = eresult = reqev->result; + uctx = reqev->ev_arg; + client = uctx->client; + soaquery = uctx->soaquery; + addr = uctx->currentserver; + INSIST(addr != NULL); + + isc_event_free(&event); + + if (eresult != ISC_R_SUCCESS) { + result = eresult; + goto out; + } + + result = dns_message_create(uctx->client->mctx, + DNS_MESSAGE_INTENTPARSE, &rcvmsg); + if (result != ISC_R_SUCCESS) + goto out; + result = dns_request_getresponse(request, rcvmsg, + DNS_MESSAGEPARSE_PRESERVEORDER); + + if (result == DNS_R_TSIGERRORSET) { + dns_request_t *newrequest = NULL; + + /* Retry SOA request without TSIG */ + dns_message_destroy(&rcvmsg); + dns_message_renderreset(uctx->soaquery); + result = dns_request_createvia3(uctx->view->requestmgr, + uctx->soaquery, NULL, addr, 0, + NULL, + client->find_timeout * 20, + client->find_timeout, 3, + uctx->client->task, + receive_soa, uctx, + &newrequest); + if (result == ISC_R_SUCCESS) { + LOCK(&uctx->lock); + dns_request_destroy(&uctx->soareq); + uctx->soareq = newrequest; + UNLOCK(&uctx->lock); + + return; + } + goto out; + } + + section = DNS_SECTION_ANSWER; + + if (rcvmsg->rcode != dns_rcode_noerror && + rcvmsg->rcode != dns_rcode_nxdomain) { + result = rcode2result(rcvmsg->rcode); + goto out; + } + + lookforsoa: + if (pass == 0) + section = DNS_SECTION_ANSWER; + else if (pass == 1) + section = DNS_SECTION_AUTHORITY; + else { + droplabel = ISC_TRUE; + goto out; + } + + result = dns_message_firstname(rcvmsg, section); + if (result != ISC_R_SUCCESS) { + pass++; + goto lookforsoa; + } + while (result == ISC_R_SUCCESS) { + name = NULL; + dns_message_currentname(rcvmsg, section, &name); + soaset = NULL; + result = dns_message_findtype(name, dns_rdatatype_soa, 0, + &soaset); + if (result == ISC_R_SUCCESS) + break; + if (section == DNS_SECTION_ANSWER) { + dns_rdataset_t *tset = NULL; + if (dns_message_findtype(name, dns_rdatatype_cname, 0, + &tset) == ISC_R_SUCCESS + || + dns_message_findtype(name, dns_rdatatype_dname, 0, + &tset) == ISC_R_SUCCESS + ) + { + seencname = ISC_TRUE; + break; + } + } + + result = dns_message_nextname(rcvmsg, section); + } + + if (soaset == NULL && !seencname) { + pass++; + goto lookforsoa; + } + + if (seencname) { + droplabel = ISC_TRUE; + goto out; + } + + result = process_soa(uctx, soaset, name); + + out: + if (droplabel) { + result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION); + INSIST(result == ISC_R_SUCCESS); + name = NULL; + dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name); + nlabels = dns_name_countlabels(name); + if (nlabels == 1) + result = DNS_R_SERVFAIL; /* is there a better error? */ + else { + dns_name_init(&tname, NULL); + dns_name_getlabelsequence(name, 1, nlabels - 1, + &tname); + dns_name_clone(&tname, name); + dns_request_destroy(&request); + LOCK(&uctx->lock); + uctx->soareq = NULL; + UNLOCK(&uctx->lock); + dns_message_renderreset(soaquery); + dns_message_settsigkey(soaquery, NULL); + result = dns_request_createvia3(uctx->view->requestmgr, + soaquery, NULL, + uctx->currentserver, 0, + uctx->tsigkey, + client->find_timeout * + 20, + client->find_timeout, + 3, client->task, + receive_soa, uctx, + &uctx->soareq); + } + } + + if (!droplabel || result != ISC_R_SUCCESS) { + dns_message_destroy(&uctx->soaquery); + LOCK(&uctx->lock); + dns_request_destroy(&uctx->soareq); + UNLOCK(&uctx->lock); + } + + if (rcvmsg != NULL) + dns_message_destroy(&rcvmsg); + + if (result != ISC_R_SUCCESS) + update_sendevent(uctx, result); +} + +static isc_result_t +request_soa(updatectx_t *uctx) { + isc_result_t result; + dns_message_t *soaquery = uctx->soaquery; + dns_name_t *name = NULL; + dns_rdataset_t *rdataset = NULL; + + if (soaquery == NULL) { + result = dns_message_create(uctx->client->mctx, + DNS_MESSAGE_INTENTRENDER, + &soaquery); + if (result != ISC_R_SUCCESS) + return (result); + } + soaquery->flags |= DNS_MESSAGEFLAG_RD; + result = dns_message_gettempname(soaquery, &name); + if (result != ISC_R_SUCCESS) + goto fail; + result = dns_message_gettemprdataset(soaquery, &rdataset); + if (result != ISC_R_SUCCESS) + goto fail; + dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa); + dns_name_clone(uctx->firstname, name); + ISC_LIST_APPEND(name->list, rdataset, link); + dns_message_addname(soaquery, name, DNS_SECTION_QUESTION); + rdataset = NULL; + name = NULL; + + result = dns_request_createvia3(uctx->view->requestmgr, + soaquery, NULL, uctx->currentserver, 0, + uctx->tsigkey, + uctx->client->find_timeout * 20, + uctx->client->find_timeout, 3, + uctx->client->task, receive_soa, uctx, + &uctx->soareq); + if (result == ISC_R_SUCCESS) { + uctx->soaquery = soaquery; + return (ISC_R_SUCCESS); + } + + fail: + if (rdataset != NULL) { + ISC_LIST_UNLINK(name->list, rdataset, link); /* for safety */ + dns_message_puttemprdataset(soaquery, &rdataset); + } + if (name != NULL) + dns_message_puttempname(soaquery, &name); + dns_message_destroy(&soaquery); + + return (result); +} + +static void +resolvesoa_done(isc_task_t *task, isc_event_t *event) { + dns_clientresevent_t *rev = (dns_clientresevent_t *)event; + updatectx_t *uctx; + dns_name_t *name, tname; + dns_rdataset_t *rdataset = NULL; + isc_result_t result = rev->result; + unsigned int nlabels; + + UNUSED(task); + + uctx = event->ev_arg; + REQUIRE(UCTX_VALID(uctx)); + + LOCK(&uctx->lock); + dns_client_destroyrestrans(&uctx->restrans); + UNLOCK(&uctx->lock); + + uctx = event->ev_arg; + if (result != ISC_R_SUCCESS && + result != DNS_R_NCACHENXDOMAIN && + result != DNS_R_NCACHENXRRSET) { + /* XXX: what about DNSSEC failure? */ + goto out; + } + + for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; + name = ISC_LIST_NEXT(name, link)) { + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + if (dns_rdataset_isassociated(rdataset) && + rdataset->type == dns_rdatatype_soa) + break; + } + } + + if (rdataset == NULL) { + /* Drop one label and retry resolution. */ + nlabels = dns_name_countlabels(&uctx->soaqname); + if (nlabels == 1) { + result = DNS_R_SERVFAIL; /* is there a better error? */ + goto out; + } + dns_name_init(&tname, NULL); + dns_name_getlabelsequence(&uctx->soaqname, 1, nlabels - 1, + &tname); + dns_name_clone(&tname, &uctx->soaqname); + + result = dns_client_startresolve(uctx->client, &uctx->soaqname, + uctx->rdclass, + dns_rdatatype_soa, 0, + uctx->client->task, + resolvesoa_done, uctx, + &uctx->restrans); + } else + result = process_soa(uctx, rdataset, &uctx->soaqname); + + out: + dns_client_freeresanswer(uctx->client, &rev->answerlist); + isc_event_free(&event); + + if (result != ISC_R_SUCCESS) + update_sendevent(uctx, result); +} + +static isc_result_t +copy_name(isc_mem_t *mctx, dns_message_t *msg, dns_name_t *name, + dns_name_t **newnamep) +{ + isc_result_t result; + dns_name_t *newname = NULL; + isc_region_t r; + isc_buffer_t *namebuf = NULL, *rdatabuf = NULL; + dns_rdatalist_t *rdatalist; + dns_rdataset_t *rdataset, *newrdataset; + dns_rdata_t rdata = DNS_RDATA_INIT, *newrdata; + + result = dns_message_gettempname(msg, &newname); + if (result != ISC_R_SUCCESS) + return (result); + result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE); + if (result != ISC_R_SUCCESS) + goto fail; + dns_name_init(newname, NULL); + dns_name_setbuffer(newname, namebuf); + dns_message_takebuffer(msg, &namebuf); + result = dns_name_copy(name, newname, NULL); + if (result != ISC_R_SUCCESS) + goto fail; + + for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + rdatalist = NULL; + result = dns_message_gettemprdatalist(msg, &rdatalist); + if (result != ISC_R_SUCCESS) + goto fail; + dns_rdatalist_init(rdatalist); + rdatalist->type = rdataset->type; + rdatalist->rdclass = rdataset->rdclass; + rdatalist->covers = rdataset->covers; + rdatalist->ttl = rdataset->ttl; + + result = dns_rdataset_first(rdataset); + while (result == ISC_R_SUCCESS) { + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); + + newrdata = NULL; + result = dns_message_gettemprdata(msg, &newrdata); + if (result != ISC_R_SUCCESS) + goto fail; + dns_rdata_toregion(&rdata, &r); + rdatabuf = NULL; + result = isc_buffer_allocate(mctx, &rdatabuf, + r.length); + if (result != ISC_R_SUCCESS) + goto fail; + isc_buffer_putmem(rdatabuf, r.base, r.length); + isc_buffer_usedregion(rdatabuf, &r); + dns_rdata_init(newrdata); + dns_rdata_fromregion(newrdata, rdata.rdclass, + rdata.type, &r); + newrdata->flags = rdata.flags; + + ISC_LIST_APPEND(rdatalist->rdata, newrdata, link); + dns_message_takebuffer(msg, &rdatabuf); + + result = dns_rdataset_next(rdataset); + } + + newrdataset = NULL; + result = dns_message_gettemprdataset(msg, &newrdataset); + if (result != ISC_R_SUCCESS) + goto fail; + dns_rdataset_init(newrdataset); + dns_rdatalist_tordataset(rdatalist, newrdataset); + + ISC_LIST_APPEND(newname->list, newrdataset, link); + } + + *newnamep = newname; + + return (ISC_R_SUCCESS); + + fail: + dns_message_puttempname(msg, &newname); + + return (result); + +} + +static void +internal_update_callback(isc_task_t *task, isc_event_t *event) { + updatearg_t *uarg = event->ev_arg; + dns_clientupdateevent_t *uev = (dns_clientupdateevent_t *)event; + + UNUSED(task); + + LOCK(&uarg->lock); + + uarg->result = uev->result; + + dns_client_destroyupdatetrans(&uarg->trans); + isc_event_free(&event); + + if (!uarg->canceled) { + UNLOCK(&uarg->lock); + + /* Exit from the internal event loop */ + isc_app_ctxsuspend(uarg->actx); + } else { + /* + * We have already exited from the loop (due to some + * unexpected event). Just clean the arg up. + */ + UNLOCK(&uarg->lock); + DESTROYLOCK(&uarg->lock); + isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg)); + } +} + +isc_result_t +dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass, + dns_name_t *zonename, dns_namelist_t *prerequisites, + dns_namelist_t *updates, isc_sockaddrlist_t *servers, + dns_tsec_t *tsec, unsigned int options) +{ + isc_result_t result; + isc_appctx_t *actx; + updatearg_t *uarg; + + REQUIRE(DNS_CLIENT_VALID(client)); + + if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 && + (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) { + /* + * If the client is run under application's control, we need + * to create a new running (sub)environment for this + * particular resolution. + */ + return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */ + } else + actx = client->actx; + + uarg = isc_mem_get(client->mctx, sizeof(*uarg)); + if (uarg == NULL) + return (ISC_R_NOMEMORY); + + result = isc_mutex_init(&uarg->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(client->mctx, uarg, sizeof(*uarg)); + return (result); + } + + uarg->actx = actx; + uarg->client = client; + uarg->result = ISC_R_FAILURE; + uarg->trans = NULL; + uarg->canceled = ISC_FALSE; + + result = dns_client_startupdate(client, rdclass, zonename, + prerequisites, updates, servers, + tsec, options, client->task, + internal_update_callback, uarg, + &uarg->trans); + if (result != ISC_R_SUCCESS) { + DESTROYLOCK(&uarg->lock); + isc_mem_put(client->mctx, uarg, sizeof(*uarg)); + return (result); + } + + /* + * Start internal event loop. It blocks until the entire process + * is completed. + */ + result = isc_app_ctxrun(actx); + + LOCK(&uarg->lock); + if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) + result = uarg->result; + + if (uarg->trans != NULL) { + /* + * Unusual termination (perhaps due to signal). We need some + * tricky cleanup process. + */ + uarg->canceled = ISC_TRUE; + dns_client_cancelupdate(uarg->trans); + + UNLOCK(&uarg->lock); + + /* uarg will be freed in the event handler. */ + } else { + UNLOCK(&uarg->lock); + + DESTROYLOCK(&uarg->lock); + isc_mem_put(client->mctx, uarg, sizeof(*uarg)); + } + + return (result); +} + +isc_result_t +dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass, + dns_name_t *zonename, dns_namelist_t *prerequisites, + dns_namelist_t *updates, isc_sockaddrlist_t *servers, + dns_tsec_t *tsec, unsigned int options, + isc_task_t *task, isc_taskaction_t action, void *arg, + dns_clientupdatetrans_t **transp) +{ + dns_view_t *view = NULL; + isc_result_t result; + dns_name_t *name, *newname; + updatectx_t *uctx; + isc_task_t *clone = NULL; + dns_section_t section = DNS_SECTION_UPDATE; + isc_sockaddr_t *server, *sa = NULL; + dns_tsectype_t tsectype = dns_tsectype_none; + + UNUSED(options); + + REQUIRE(DNS_CLIENT_VALID(client)); + REQUIRE(transp != NULL && *transp == NULL); + REQUIRE(updates != NULL); + REQUIRE(task != NULL); + + if (tsec != NULL) { + tsectype = dns_tsec_gettype(tsec); + if (tsectype != dns_tsectype_tsig) + return (ISC_R_NOTIMPLEMENTED); /* XXX */ + } + + LOCK(&client->lock); + result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, + rdclass, &view); + UNLOCK(&client->lock); + if (result != ISC_R_SUCCESS) + return (result); + + /* Create a context and prepare some resources */ + uctx = isc_mem_get(client->mctx, sizeof(*uctx)); + if (uctx == NULL) { + dns_view_detach(&view); + return (ISC_R_NOMEMORY); + } + result = isc_mutex_init(&uctx->lock); + if (result != ISC_R_SUCCESS) { + dns_view_detach(&view); + isc_mem_put(client->mctx, uctx, sizeof(*uctx)); + return (ISC_R_NOMEMORY); + } + clone = NULL; + isc_task_attach(task, &clone); + uctx->client = client; + ISC_LINK_INIT(uctx, link); + uctx->state = dns_clientupdatestate_prepare; + uctx->view = view; + uctx->rdclass = rdclass; + uctx->canceled = ISC_FALSE; + uctx->updatemsg = NULL; + uctx->soaquery = NULL; + uctx->updatereq = NULL; + uctx->restrans = NULL; + uctx->restrans2 = NULL; + uctx->bp4 = NULL; + uctx->bp6 = NULL; + uctx->soareq = NULL; + uctx->event = NULL; + uctx->tsigkey = NULL; + uctx->sig0key = NULL; + uctx->zonename = NULL; + dns_name_init(&uctx->soaqname, NULL); + ISC_LIST_INIT(uctx->servers); + uctx->nservers = 0; + uctx->currentserver = NULL; + dns_fixedname_init(&uctx->zonefname); + if (tsec != NULL) + dns_tsec_getkey(tsec, &uctx->tsigkey); + uctx->event = (dns_clientupdateevent_t *) + isc_event_allocate(client->mctx, clone, DNS_EVENT_UPDATEDONE, + action, arg, sizeof(*uctx->event)); + if (uctx->event == NULL) + goto fail; + if (zonename != NULL) { + uctx->zonename = dns_fixedname_name(&uctx->zonefname); + result = dns_name_copy(zonename, uctx->zonename, NULL); + } + if (servers != NULL) { + for (server = ISC_LIST_HEAD(*servers); + server != NULL; + server = ISC_LIST_NEXT(server, link)) { + sa = isc_mem_get(client->mctx, sizeof(*sa)); + if (sa == NULL) + goto fail; + sa->type = server->type; + sa->length = server->length; + ISC_LINK_INIT(sa, link); + ISC_LIST_APPEND(uctx->servers, sa, link); + if (uctx->currentserver == NULL) + uctx->currentserver = sa; + uctx->nservers++; + } + } + + /* Make update message */ + result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER, + &uctx->updatemsg); + if (result != ISC_R_SUCCESS) + goto fail; + uctx->updatemsg->opcode = dns_opcode_update; + + if (prerequisites != NULL) { + for (name = ISC_LIST_HEAD(*prerequisites); name != NULL; + name = ISC_LIST_NEXT(name, link)) { + newname = NULL; + result = copy_name(client->mctx, uctx->updatemsg, + name, &newname); + if (result != ISC_R_SUCCESS) + goto fail; + dns_message_addname(uctx->updatemsg, newname, + DNS_SECTION_PREREQUISITE); + } + } + + for (name = ISC_LIST_HEAD(*updates); name != NULL; + name = ISC_LIST_NEXT(name, link)) { + newname = NULL; + result = copy_name(client->mctx, uctx->updatemsg, name, + &newname); + if (result != ISC_R_SUCCESS) + goto fail; + dns_message_addname(uctx->updatemsg, newname, + DNS_SECTION_UPDATE); + } + + uctx->firstname = NULL; + result = dns_message_firstname(uctx->updatemsg, section); + if (result == ISC_R_NOMORE) { + section = DNS_SECTION_PREREQUISITE; + result = dns_message_firstname(uctx->updatemsg, section); + } + if (result != ISC_R_SUCCESS) + goto fail; + dns_message_currentname(uctx->updatemsg, section, &uctx->firstname); + + uctx->magic = UCTX_MAGIC; + + LOCK(&client->lock); + ISC_LIST_APPEND(client->updatectxs, uctx, link); + UNLOCK(&client->lock); + + if (uctx->zonename != NULL && uctx->currentserver != NULL) { + result = send_update(uctx); + if (result != ISC_R_SUCCESS) + goto fail; + } else if (uctx->currentserver != NULL) { + result = request_soa(uctx); + if (result != ISC_R_SUCCESS) + goto fail; + } else { + dns_name_clone(uctx->firstname, &uctx->soaqname); + result = dns_client_startresolve(uctx->client, &uctx->soaqname, + uctx->rdclass, + dns_rdatatype_soa, 0, + client->task, resolvesoa_done, + uctx, &uctx->restrans); + if (result != ISC_R_SUCCESS) + goto fail; + } + + *transp = (dns_clientupdatetrans_t *)uctx; + + return (ISC_R_SUCCESS); + + fail: + if (ISC_LINK_LINKED(uctx, link)) { + LOCK(&client->lock); + ISC_LIST_UNLINK(client->updatectxs, uctx, link); + UNLOCK(&client->lock); + } + if (uctx->updatemsg != NULL) + dns_message_destroy(&uctx->updatemsg); + while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) { + ISC_LIST_UNLINK(uctx->servers, sa, link); + isc_mem_put(client->mctx, sa, sizeof(*sa)); + } + if (uctx->event != NULL) + isc_event_free(ISC_EVENT_PTR(&uctx->event)); + if (uctx->tsigkey != NULL) + dns_tsigkey_detach(&uctx->tsigkey); + isc_task_detach(&clone); + DESTROYLOCK(&uctx->lock); + uctx->magic = 0; + isc_mem_put(client->mctx, uctx, sizeof(*uctx)); + dns_view_detach(&view); + + return (result); +} + +void +dns_client_cancelupdate(dns_clientupdatetrans_t *trans) { + updatectx_t *uctx; + + REQUIRE(trans != NULL); + uctx = (updatectx_t *)trans; + REQUIRE(UCTX_VALID(uctx)); + + LOCK(&uctx->lock); + + if (!uctx->canceled) { + uctx->canceled = ISC_TRUE; + if (uctx->updatereq != NULL) + dns_request_cancel(uctx->updatereq); + if (uctx->soareq != NULL) + dns_request_cancel(uctx->soareq); + if (uctx->restrans != NULL) + dns_client_cancelresolve(uctx->restrans); + if (uctx->restrans2 != NULL) + dns_client_cancelresolve(uctx->restrans2); + } + + UNLOCK(&uctx->lock); +} + +void +dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) { + updatectx_t *uctx; + isc_mem_t *mctx; + dns_client_t *client; + isc_boolean_t need_destroyclient = ISC_FALSE; + isc_sockaddr_t *sa; + + REQUIRE(transp != NULL); + uctx = (updatectx_t *)*transp; + REQUIRE(UCTX_VALID(uctx)); + client = uctx->client; + REQUIRE(DNS_CLIENT_VALID(client)); + REQUIRE(uctx->updatereq == NULL && uctx->updatemsg == NULL && + uctx->soareq == NULL && uctx->soaquery == NULL && + uctx->event == NULL && uctx->tsigkey == NULL && + uctx->sig0key == NULL); + + mctx = client->mctx; + dns_view_detach(&uctx->view); + while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) { + ISC_LIST_UNLINK(uctx->servers, sa, link); + isc_mem_put(mctx, sa, sizeof(*sa)); + } + + LOCK(&client->lock); + + INSIST(ISC_LINK_LINKED(uctx, link)); + ISC_LIST_UNLINK(client->updatectxs, uctx, link); + + if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) && + ISC_LIST_EMPTY(client->reqctxs) && + ISC_LIST_EMPTY(client->updatectxs)) + need_destroyclient = ISC_TRUE; + + UNLOCK(&client->lock); + + DESTROYLOCK(&uctx->lock); + uctx->magic = 0; + + isc_mem_put(mctx, uctx, sizeof(*uctx)); + + if (need_destroyclient) + destroyclient(&client); + + *transp = NULL; +} + +isc_mem_t * +dns_client_mctx(dns_client_t *client) { + + REQUIRE(DNS_CLIENT_VALID(client)); + return (client->mctx); +} + +typedef struct { + isc_buffer_t buffer; + dns_rdataset_t rdataset; + dns_rdatalist_t rdatalist; + dns_rdata_t rdata; + size_t size; + isc_mem_t * mctx; + unsigned char data[FLEXIBLE_ARRAY_MEMBER]; +} dns_client_updaterec_t; + +isc_result_t +dns_client_updaterec(dns_client_updateop_t op, dns_name_t *owner, + dns_rdatatype_t type, dns_rdata_t *source, + dns_ttl_t ttl, dns_name_t *target, + dns_rdataset_t *rdataset, dns_rdatalist_t *rdatalist, + dns_rdata_t *rdata, isc_mem_t *mctx) +{ + dns_client_updaterec_t *updaterec = NULL; + size_t size = offsetof(dns_client_updaterec_t, data); + + REQUIRE(op < updateop_max); + REQUIRE(owner != NULL); + REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) || + (rdataset == NULL && rdatalist == NULL && rdata == NULL && + mctx != NULL)); + if (op == updateop_add) + REQUIRE(source != NULL); + if (source != NULL) { + REQUIRE(source->type == type); + REQUIRE(op == updateop_add || op == updateop_delete || + op == updateop_exist); + } + + size += owner->length; + if (source != NULL) + size += source->length; + + if (rdataset == NULL) { + updaterec = isc_mem_get(mctx, size); + if (updaterec == NULL) + return (ISC_R_NOMEMORY); + rdataset = &updaterec->rdataset; + rdatalist = &updaterec->rdatalist; + rdata = &updaterec->rdata; + dns_rdataset_init(rdataset); + dns_rdatalist_init(&updaterec->rdatalist); + dns_rdata_init(&updaterec->rdata); + isc_buffer_init(&updaterec->buffer, updaterec->data, + size - offsetof(dns_client_updaterec_t, data)); + dns_name_copy(owner, target, &updaterec->buffer); + if (source != NULL) { + isc_region_t r; + dns_rdata_clone(source, rdata); + dns_rdata_toregion(rdata, &r); + rdata->data = isc_buffer_used(&updaterec->buffer); + isc_buffer_copyregion(&updaterec->buffer, &r); + } + updaterec->mctx = NULL; + isc_mem_attach(mctx, &updaterec->mctx); + } else if (source != NULL) + dns_rdata_clone(source, rdata); + + switch (op) { + case updateop_add: + break; + case updateop_delete: + if (source != NULL) { + ttl = 0; + dns_rdata_makedelete(rdata); + } else + dns_rdata_deleterrset(rdata, type); + break; + case updateop_notexist: + dns_rdata_notexist(rdata, type); + break; + case updateop_exist: + if (source == NULL) { + ttl = 0; + dns_rdata_exists(rdata, type); + } + case updateop_none: + break; + default: + INSIST(0); + } + + rdatalist->type = rdata->type; + rdatalist->rdclass = rdata->rdclass; + if (source != NULL) { + rdatalist->covers = dns_rdata_covers(rdata); + rdatalist->ttl = ttl; + } + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + dns_rdatalist_tordataset(rdatalist, rdataset); + ISC_LIST_APPEND(target->list, rdataset, link); + if (updaterec != NULL) { + target->attributes |= DNS_NAMEATTR_HASUPDATEREC; + dns_name_setbuffer(target, &updaterec->buffer); + } + if (op == updateop_add || op == updateop_delete) + target->attributes |= DNS_NAMEATTR_UPDATE; + else + target->attributes |= DNS_NAMEATTR_PREREQUISITE; + return (ISC_R_SUCCESS); +} + +void +dns_client_freeupdate(dns_name_t **namep) { + dns_client_updaterec_t *updaterec; + dns_rdatalist_t *rdatalist; + dns_rdataset_t *rdataset; + dns_rdata_t *rdata; + dns_name_t *name; + + REQUIRE(namep != NULL && *namep != NULL); + + name = *namep; + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_HEAD(name->list)) { + ISC_LIST_UNLINK(name->list, rdataset, link); + rdatalist = NULL; + dns_rdatalist_fromrdataset(rdataset, &rdatalist); + if (rdatalist == NULL) { + dns_rdataset_disassociate(rdataset); + continue; + } + for (rdata = ISC_LIST_HEAD(rdatalist->rdata); + rdata != NULL; + rdata = ISC_LIST_HEAD(rdatalist->rdata)) + ISC_LIST_UNLINK(rdatalist->rdata, rdata, link); + dns_rdataset_disassociate(rdataset); + } + + if ((name->attributes & DNS_NAMEATTR_HASUPDATEREC) != 0) { + updaterec = (dns_client_updaterec_t *)name->buffer; + INSIST(updaterec != NULL); + isc_mem_putanddetach(&updaterec->mctx, updaterec, + updaterec->size); + *namep = NULL; + } +} diff --git a/lib/dns/db.c b/lib/dns/db.c index f52f674..c74d24d 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: db.c,v 1.88.50.2 2009-06-23 00:19:34 tbox Exp $ */ +/* $Id: db.c,v 1.97 2011-01-13 04:59:25 tbox Exp $ */ /*! \file */ @@ -34,10 +34,12 @@ #include #include +#include #include #include #include #include +#include #include /*** @@ -61,14 +63,18 @@ struct dns_dbimplementation { */ #include "rbtdb.h" +#ifdef BIND9 #include "rbtdb64.h" +#endif static ISC_LIST(dns_dbimplementation_t) implementations; static isc_rwlock_t implock; static isc_once_t once = ISC_ONCE_INIT; static dns_dbimplementation_t rbtimp; +#ifdef BIND9 static dns_dbimplementation_t rbt64imp; +#endif static void initialize(void) { @@ -80,15 +86,19 @@ initialize(void) { rbtimp.driverarg = NULL; ISC_LINK_INIT(&rbtimp, link); +#ifdef BIND9 rbt64imp.name = "rbt64"; rbt64imp.create = dns_rbtdb64_create; rbt64imp.mctx = NULL; rbt64imp.driverarg = NULL; ISC_LINK_INIT(&rbt64imp, link); +#endif ISC_LIST_INIT(implementations); ISC_LIST_APPEND(implementations, &rbtimp, link); +#ifdef BIND9 ISC_LIST_APPEND(implementations, &rbt64imp, link); +#endif } static inline dns_dbimplementation_t * @@ -290,6 +300,7 @@ dns_db_class(dns_db_t *db) { return (db->rdclass); } +#ifdef BIND9 isc_result_t dns_db_beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) { @@ -318,14 +329,19 @@ dns_db_endload(dns_db_t *db, dns_dbload_t **dbloadp) { isc_result_t dns_db_load(dns_db_t *db, const char *filename) { - return (dns_db_load2(db, filename, dns_masterformat_text)); + return (dns_db_load3(db, filename, dns_masterformat_text, 0)); } isc_result_t dns_db_load2(dns_db_t *db, const char *filename, dns_masterformat_t format) { + return (dns_db_load3(db, filename, format, 0)); +} + +isc_result_t +dns_db_load3(dns_db_t *db, const char *filename, dns_masterformat_t format, + unsigned int options) { isc_result_t result, eresult; dns_rdatacallbacks_t callbacks; - unsigned int options = 0; /* * Load master file 'filename' into 'db'. @@ -376,6 +392,7 @@ dns_db_dump2(dns_db_t *db, dns_dbversion_t *version, const char *filename, return ((db->methods->dump)(db, version, filename, masterformat)); } +#endif /* BIND9 */ /*** *** Version Methods @@ -921,8 +938,27 @@ dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name) } void -dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version) +dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset, + dns_dbversion_t *version) { if (db->methods->resigned != NULL) (db->methods->resigned)(db, rdataset, version); } + +void +dns_db_rpz_enabled(dns_db_t *db, dns_rpz_st_t *st) +{ + if (db->methods->rpz_enabled != NULL) + (db->methods->rpz_enabled)(db, st); +} + +isc_result_t +dns_db_rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type, + dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, + dns_rdataset_t *ardataset, dns_rpz_st_t *st) +{ + if (db->methods->rpz_findips == NULL) + return (ISC_R_NOTIMPLEMENTED); + return ((db->methods->rpz_findips)(rpz, rpz_type, zone, db, version, + ardataset, st)); +} diff --git a/lib/dns/diff.c b/lib/dns/diff.c index a92a496..3dbb5cf 100644 --- a/lib/dns/diff.c +++ b/lib/dns/diff.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: diff.c,v 1.18.50.2 2009-01-05 23:47:22 tbox Exp $ */ +/* $Id: diff.c,v 1.23 2009-12-01 00:47:09 each Exp $ */ /*! \file */ @@ -387,10 +387,22 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, * from a server that is not as careful. * Issue a warning and continue. */ - if (warn) + if (warn) { + char classbuf[DNS_RDATATYPE_FORMATSIZE]; + char namebuf[DNS_NAME_FORMATSIZE]; + + dns_name_format(dns_db_origin(db), + namebuf, + sizeof(namebuf)); + dns_rdataclass_format(dns_db_class(db), + classbuf, + sizeof(classbuf)); isc_log_write(DIFF_COMMON_LOGARGS, ISC_LOG_WARNING, - "update with no effect"); + "%s/%s: dns_diff_apply: " + "update with no effect", + namebuf, classbuf); + } } else if (result == DNS_R_NXRRSET) { /* * OK. @@ -478,6 +490,7 @@ dns_diff_load(dns_diff_t *diff, dns_addrdatasetfunc_t addfunc, if (result == DNS_R_UNCHANGED) { isc_log_write(DIFF_COMMON_LOGARGS, ISC_LOG_WARNING, + "dns_diff_load: " "update with no effect"); } else if (result == ISC_R_SUCCESS || result == DNS_R_NXRRSET) { diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 632d349..c074911 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dispatch.c,v 1.155.12.11 2009-12-02 23:26:28 marka Exp $ */ +/* $Id: dispatch.c,v 1.168.248.1.2.1 2011-06-02 23:47:34 tbox Exp $ */ /*! \file */ @@ -417,7 +417,7 @@ request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, /*% * ARC4 random number generator derived from OpenBSD. - * Only dispatch_arc4random() and dispatch_arc4uniformrandom() are expected + * Only dispatch_random() and dispatch_uniformrandom() are expected * to be called from general dispatch routines; the rest of them are subroutines * for these two. * @@ -437,8 +437,11 @@ request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifdef BIND9 static void -dispatch_arc4init(arc4ctx_t *actx, isc_entropy_t *entropy, isc_mutex_t *lock) { +dispatch_initrandom(arc4ctx_t *actx, isc_entropy_t *entropy, + isc_mutex_t *lock) +{ int n; for (n = 0; n < 256; n++) actx->s[n] = n; @@ -527,7 +530,7 @@ dispatch_arc4stir(arc4ctx_t *actx) { } static isc_uint16_t -dispatch_arc4random(arc4ctx_t *actx) { +dispatch_random(arc4ctx_t *actx) { isc_uint16_t result; if (actx->lock != NULL) @@ -543,9 +546,38 @@ dispatch_arc4random(arc4ctx_t *actx) { return (result); } +#else +/* + * For general purpose library, we don't have to be too strict about the + * quality of random values. Performance doesn't matter much, either. + * So we simply use the isc_random module to keep the library as small as + * possible. + */ + +static void +dispatch_initrandom(arc4ctx_t *actx, isc_entropy_t *entropy, + isc_mutex_t *lock) +{ + UNUSED(actx); + UNUSED(entropy); + UNUSED(lock); + + return; +} static isc_uint16_t -dispatch_arc4uniformrandom(arc4ctx_t *actx, isc_uint16_t upper_bound) { +dispatch_random(arc4ctx_t *actx) { + isc_uint32_t r; + + UNUSED(actx); + + isc_random_get(&r); + return (r & 0xffff); +} +#endif /* BIND9 */ + +static isc_uint16_t +dispatch_uniformrandom(arc4ctx_t *actx, isc_uint16_t upper_bound) { isc_uint16_t min, r; if (upper_bound < 2) @@ -568,7 +600,7 @@ dispatch_arc4uniformrandom(arc4ctx_t *actx, isc_uint16_t upper_bound) { * to re-roll. */ for (;;) { - r = dispatch_arc4random(actx); + r = dispatch_random(actx); if (r >= min) break; } @@ -859,7 +891,7 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest, */ localaddr = disp->local; for (i = 0; i < 64; i++) { - port = ports[dispatch_arc4uniformrandom(DISP_ARC4CTX(disp), + port = ports[dispatch_uniformrandom(DISP_ARC4CTX(disp), nports)]; isc_sockaddr_setport(&localaddr, port); @@ -964,6 +996,7 @@ deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) { INSIST(dispsock->portentry != NULL); deref_portentry(disp, &dispsock->portentry); +#ifdef BIND9 if (disp->nsockets > DNS_DISPATCH_POOLSOCKS) destroy_dispsocket(disp, &dispsock); else { @@ -987,6 +1020,13 @@ deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) { destroy_dispsocket(disp, &dispsock); } } +#else + /* This kind of optimization isn't necessary for normal use */ + UNUSED(qid); + UNUSED(result); + + destroy_dispsocket(disp, &dispsock); +#endif } /* @@ -1707,13 +1747,17 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) { isc_mempool_destroy(&mgr->epool); isc_mempool_destroy(&mgr->rpool); isc_mempool_destroy(&mgr->dpool); - isc_mempool_destroy(&mgr->bpool); - isc_mempool_destroy(&mgr->spool); + if (mgr->bpool != NULL) + isc_mempool_destroy(&mgr->bpool); + if (mgr->spool != NULL) + isc_mempool_destroy(&mgr->spool); DESTROYLOCK(&mgr->pool_lock); +#ifdef BIND9 if (mgr->entropy != NULL) isc_entropy_detach(&mgr->entropy); +#endif /* BIND9 */ if (mgr->qid != NULL) qid_destroy(mctx, &mgr->qid); @@ -1752,9 +1796,13 @@ open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local, return (result); isc_socket_setname(sock, "dispatcher", NULL); } else { +#ifdef BIND9 result = isc_socket_open(sock); if (result != ISC_R_SUCCESS) return (result); +#else + INSIST(0); +#endif } #ifndef ISC_ALLOW_MAPPED @@ -1764,8 +1812,13 @@ open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local, if (result != ISC_R_SUCCESS) { if (*sockp == NULL) isc_socket_detach(&sock); - else + else { +#ifdef BIND9 isc_socket_close(sock); +#else + INSIST(0); +#endif + } return (result); } @@ -1897,10 +1950,14 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy, if (result != ISC_R_SUCCESS) goto kill_dpool; +#ifdef BIND9 if (entropy != NULL) isc_entropy_attach(entropy, &mgr->entropy); +#else + UNUSED(entropy); +#endif - dispatch_arc4init(&mgr->arc4ctx, mgr->entropy, &mgr->arc4_lock); + dispatch_initrandom(&mgr->arc4ctx, mgr->entropy, &mgr->arc4_lock); *mgrp = mgr; return (ISC_R_SUCCESS); @@ -2411,7 +2468,7 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, ISC_LIST_INIT(disp->activesockets); ISC_LIST_INIT(disp->inactivesockets); disp->nsockets = 0; - dispatch_arc4init(&disp->arc4ctx, mgr->entropy, NULL); + dispatch_initrandom(&disp->arc4ctx, mgr->entropy, NULL); disp->port_table = NULL; disp->portpool = NULL; @@ -2708,7 +2765,7 @@ get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, for (i = 0; i < 1024; i++) { in_port_t prt; - prt = ports[dispatch_arc4uniformrandom( + prt = ports[dispatch_uniformrandom( DISP_ARC4CTX(disp), nports)]; isc_sockaddr_setport(&localaddr_bound, prt); @@ -2844,8 +2901,10 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, disp->task[i] = NULL; result = isc_task_create(taskmgr, 0, &disp->task[i]); if (result != ISC_R_SUCCESS) { - while (--i >= 0) - isc_task_destroy(&disp->task[i]); + while (--i >= 0) { + isc_task_shutdown(disp->task[i]); + isc_task_detach(&disp->task[i]); + } goto kill_socket; } isc_task_setname(disp->task[i], "udpdispatch", disp); @@ -3045,7 +3104,7 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, /* * Try somewhat hard to find an unique ID. */ - id = (dns_messageid_t)dispatch_arc4random(DISP_ARC4CTX(disp)); + id = (dns_messageid_t)dispatch_random(DISP_ARC4CTX(disp)); bucket = dns_hash(qid, dest, id, localport); ok = ISC_FALSE; for (i = 0; i < 64; i++) { diff --git a/lib/dns/dlz.c b/lib/dns/dlz.c index f848230..5a508e9 100644 --- a/lib/dns/dlz.c +++ b/lib/dns/dlz.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2005, 2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -50,7 +50,7 @@ * USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dlz.c,v 1.5.332.2 2009-01-18 23:47:35 tbox Exp $ */ +/* $Id: dlz.c,v 1.10 2010-12-20 23:47:20 tbox Exp $ */ /*! \file */ @@ -64,6 +64,8 @@ #include #include #include +#include +#include #include @@ -230,6 +232,12 @@ dns_dlzdestroy(dns_dlzdb_t **dbp) { */ REQUIRE(dbp != NULL && DNS_DLZ_VALID(*dbp)); +#ifdef BIND9 + if ((*dbp)->ssutable != NULL) { + dns_ssutable_detach(&(*dbp)->ssutable); + } +#endif + /* call the drivers destroy method */ if ((*dbp) != NULL) { mctx = (*dbp)->mctx; @@ -499,7 +507,7 @@ dns_dlzunregister(dns_dlzimplementation_t **dlzimp) { mctx = dlz_imp->mctx; /* - * return the memory back to the available memory pool and + * Return the memory back to the available memory pool and * remove it from the memory context. */ isc_mem_put(mctx, dlz_imp, sizeof(dns_dlzimplementation_t)); @@ -508,3 +516,143 @@ dns_dlzunregister(dns_dlzimplementation_t **dlzimp) { /* Unlock the dlz_implementations list. */ RWUNLOCK(&dlz_implock, isc_rwlocktype_write); } + +#ifdef BIND9 +/* + * Create a writeable DLZ zone. This can be called by DLZ drivers + * during configure() to create a zone that can be updated. The zone + * type is set to dns_zone_dlz, which is equivalent to a master zone + * + * This function uses a callback setup in dns_dlzconfigure() to call + * into the server zone code to setup the remaining pieces of server + * specific functionality on the zone + */ +isc_result_t +dns_dlz_writeablezone(dns_view_t *view, const char *zone_name) { + dns_zone_t *zone = NULL; + dns_zone_t *dupzone = NULL; + isc_result_t result; + isc_buffer_t buffer; + dns_fixedname_t fixorigin; + dns_name_t *origin; + dns_rdataclass_t zclass; + dns_dlzdb_t *dlzdatabase; + + REQUIRE(DNS_DLZ_VALID(view->dlzdatabase)); + + dlzdatabase = view->dlzdatabase; + + REQUIRE(dlzdatabase->configure_callback != NULL); + + isc_buffer_init(&buffer, zone_name, strlen(zone_name)); + isc_buffer_add(&buffer, strlen(zone_name)); + dns_fixedname_init(&fixorigin); + result = dns_name_fromtext(dns_fixedname_name(&fixorigin), + &buffer, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + origin = dns_fixedname_name(&fixorigin); + + zclass = view->rdclass; + + /* See if the zone already exists */ + result = dns_view_findzone(view, origin, &dupzone); + if (result == ISC_R_SUCCESS) { + dns_zone_detach(&dupzone); + result = ISC_R_EXISTS; + goto cleanup; + } + INSIST(dupzone == NULL); + + /* Create it */ + result = dns_zone_create(&zone, view->mctx); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_zone_setorigin(zone, origin); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_zone_setview(zone, view); + + dns_zone_setadded(zone, ISC_TRUE); + + if (dlzdatabase->ssutable == NULL) { + result = dns_ssutable_createdlz(dlzdatabase->mctx, + &dlzdatabase->ssutable, + view->dlzdatabase); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + dns_zone_setssutable(zone, dlzdatabase->ssutable); + + result = dlzdatabase->configure_callback(view, zone); + if (result != ISC_R_SUCCESS) + goto cleanup; + + /* + * Add the zone to its view in the new view list. + */ + result = dns_view_addzone(view, zone); + + result = ISC_R_SUCCESS; + + cleanup: + if (zone != NULL) + dns_zone_detach(&zone); + + return (result); +} +#endif + +/*% + * Configure a DLZ driver. This is optional, and if supplied gives + * the backend an opportunity to configure parameters related to DLZ. + */ +isc_result_t +dns_dlzconfigure(dns_view_t *view, isc_result_t (*callback)(dns_view_t *, + dns_zone_t *)) +{ + dns_dlzimplementation_t *impl; + dns_dlzdb_t *dlzdatabase; + isc_result_t result; + + REQUIRE(view != NULL); + REQUIRE(DNS_DLZ_VALID(view->dlzdatabase)); + REQUIRE(view->dlzdatabase->implementation != NULL); + + dlzdatabase = view->dlzdatabase; + impl = dlzdatabase->implementation; + + if (impl->methods->configure == NULL) + return (ISC_R_SUCCESS); + + dlzdatabase->configure_callback = callback; + + result = impl->methods->configure(impl->driverarg, + dlzdatabase->dbdata, view); + return (result); +} + +isc_boolean_t +dns_dlz_ssumatch(dns_dlzdb_t *dlzdatabase, + dns_name_t *signer, dns_name_t *name, isc_netaddr_t *tcpaddr, + dns_rdatatype_t type, const dst_key_t *key) +{ + dns_dlzimplementation_t *impl; + isc_boolean_t r; + + REQUIRE(dlzdatabase != NULL); + REQUIRE(dlzdatabase->implementation != NULL); + REQUIRE(dlzdatabase->implementation->methods != NULL); + impl = dlzdatabase->implementation; + + if (impl->methods->ssumatch == NULL) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_INFO, + "No ssumatch method for DLZ database"); + return (ISC_FALSE); + } + + r = impl->methods->ssumatch(signer, name, tcpaddr, type, key, + impl->driverarg, dlzdatabase->dbdata); + return (r); +} diff --git a/lib/dns/dns64.c b/lib/dns/dns64.c new file mode 100644 index 0000000..180c0a9 --- /dev/null +++ b/lib/dns/dns64.c @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: dns64.c,v 1.6 2010-12-09 04:59:09 marka Exp $ */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct dns_dns64 { + unsigned char bits[16]; /* + * Prefix + suffix bits. + */ + dns_acl_t * clients; /* + * Which clients get mapped + * addresses. + */ + dns_acl_t * mapped; /* + * IPv4 addresses to be mapped. + */ + dns_acl_t * excluded; /* + * IPv6 addresses that are + * treated as not existing. + */ + unsigned int prefixlen; /* + * Start of mapped address. + */ + unsigned int flags; + isc_mem_t * mctx; + ISC_LINK(dns_dns64_t) link; +}; + +isc_result_t +dns_dns64_create(isc_mem_t *mctx, isc_netaddr_t *prefix, + unsigned int prefixlen, isc_netaddr_t *suffix, + dns_acl_t *clients, dns_acl_t *mapped, dns_acl_t *excluded, + unsigned int flags, dns_dns64_t **dns64) +{ + dns_dns64_t *new; + unsigned int nbytes = 16; + + REQUIRE(prefix != NULL && prefix->family == AF_INET6); + /* Legal prefix lengths from draft-ietf-behave-address-format-04. */ + REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 || + prefixlen == 56 || prefixlen == 64 || prefixlen == 96); + REQUIRE(isc_netaddr_prefixok(prefix, prefixlen) == ISC_R_SUCCESS); + REQUIRE(dns64 != NULL && *dns64 == NULL); + + if (suffix != NULL) { + static const unsigned char zeros[16]; + REQUIRE(prefix->family == AF_INET6); + nbytes = prefixlen / 8 + 4; + /* Bits 64-71 are zeros. draft-ietf-behave-address-format-04 */ + if (prefixlen >= 32 && prefixlen <= 64) + nbytes++; + REQUIRE(memcmp(suffix->type.in6.s6_addr, zeros, nbytes) == 0); + } + + new = isc_mem_get(mctx, sizeof(dns_dns64_t)); + if (new == NULL) + return (ISC_R_NOMEMORY); + memset(new->bits, 0, sizeof(new->bits)); + memcpy(new->bits, prefix->type.in6.s6_addr, prefixlen / 8); + if (suffix != NULL) + memcpy(new->bits + nbytes, suffix->type.in6.s6_addr + nbytes, + 16 - nbytes); + new->clients = NULL; + if (clients != NULL) + dns_acl_attach(clients, &new->clients); + new->mapped = NULL; + if (mapped != NULL) + dns_acl_attach(mapped, &new->mapped); + new->excluded = NULL; + if (excluded != NULL) + dns_acl_attach(excluded, &new->excluded); + new->prefixlen = prefixlen; + new->flags = flags; + ISC_LINK_INIT(new, link); + new->mctx = NULL; + isc_mem_attach(mctx, &new->mctx); + *dns64 = new; + return (ISC_R_SUCCESS); +} + +void +dns_dns64_destroy(dns_dns64_t **dns64p) { + dns_dns64_t *dns64; + + REQUIRE(dns64p != NULL && *dns64p != NULL); + + dns64 = *dns64p; + *dns64p = NULL; + + REQUIRE(!ISC_LINK_LINKED(dns64, link)); + + if (dns64->clients != NULL) + dns_acl_detach(&dns64->clients); + if (dns64->mapped != NULL) + dns_acl_detach(&dns64->mapped); + if (dns64->excluded != NULL) + dns_acl_detach(&dns64->excluded); + isc_mem_putanddetach(&dns64->mctx, dns64, sizeof(*dns64)); +} + +isc_result_t +dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, + const dns_name_t *reqsigner, const dns_aclenv_t *env, + unsigned int flags, unsigned char *a, unsigned char *aaaa) +{ + unsigned int nbytes, i; + isc_result_t result; + int match; + + if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 && + (flags & DNS_DNS64_RECURSIVE) == 0) + return (DNS_R_DISALLOWED); + + if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 && + (flags & DNS_DNS64_DNSSEC) != 0) + return (DNS_R_DISALLOWED); + + if (dns64->clients != NULL) { + result = dns_acl_match(reqaddr, reqsigner, dns64->clients, env, + &match, NULL); + if (result != ISC_R_SUCCESS) + return (result); + if (match <= 0) + return (DNS_R_DISALLOWED); + } + + if (dns64->mapped != NULL) { + struct in_addr ina; + isc_netaddr_t netaddr; + + memcpy(&ina.s_addr, a, 4); + isc_netaddr_fromin(&netaddr, &ina); + result = dns_acl_match(&netaddr, NULL, dns64->mapped, env, + &match, NULL); + if (result != ISC_R_SUCCESS) + return (result); + if (match <= 0) + return (DNS_R_DISALLOWED); + } + + nbytes = dns64->prefixlen / 8; + INSIST(nbytes <= 12); + /* Copy prefix. */ + memcpy(aaaa, dns64->bits, nbytes); + /* Bits 64-71 are zeros. draft-ietf-behave-address-format-04 */ + if (nbytes == 8) + aaaa[nbytes++] = 0; + /* Copy mapped address. */ + for (i = 0; i < 4U; i++) { + aaaa[nbytes++] = a[i]; + /* Bits 64-71 are zeros. draft-ietf-behave-address-format-04 */ + if (nbytes == 8) + aaaa[nbytes++] = 0; + } + /* Copy suffix. */ + memcpy(aaaa + nbytes, dns64->bits + nbytes, 16 - nbytes); + return (ISC_R_SUCCESS); +} + +dns_dns64_t * +dns_dns64_next(dns_dns64_t *dns64) { + dns64 = ISC_LIST_NEXT(dns64, link); + return (dns64); +} + +void +dns_dns64_append(dns_dns64list_t *list, dns_dns64_t *dns64) { + ISC_LIST_APPEND(*list, dns64, link); +} + +void +dns_dns64_unlink(dns_dns64list_t *list, dns_dns64_t *dns64) { + ISC_LIST_UNLINK(*list, dns64, link); +} + +isc_boolean_t +dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, + const dns_name_t *reqsigner, const dns_aclenv_t *env, + unsigned int flags, dns_rdataset_t *rdataset, + isc_boolean_t *aaaaok, size_t aaaaoklen) +{ + struct in6_addr in6; + isc_netaddr_t netaddr; + isc_result_t result; + int match; + isc_boolean_t answer = ISC_FALSE; + isc_boolean_t found = ISC_FALSE; + unsigned int i, ok; + + REQUIRE(rdataset != NULL); + REQUIRE(rdataset->type == dns_rdatatype_aaaa); + REQUIRE(rdataset->rdclass == dns_rdataclass_in); + if (aaaaok != NULL) + REQUIRE(aaaaoklen == dns_rdataset_count(rdataset)); + + for (;dns64 != NULL; dns64 = ISC_LIST_NEXT(dns64, link)) { + if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 && + (flags & DNS_DNS64_RECURSIVE) == 0) + continue; + + if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 && + (flags & DNS_DNS64_DNSSEC) != 0) + continue; + /* + * Work out if this dns64 structure applies to this client. + */ + if (dns64->clients != NULL) { + result = dns_acl_match(reqaddr, reqsigner, + dns64->clients, env, + &match, NULL); + if (result != ISC_R_SUCCESS) + continue; + if (match <= 0) + continue; + } + + if (!found && aaaaok != NULL) { + for (i = 0; i < aaaaoklen; i++) + aaaaok[i] = ISC_FALSE; + } + found = ISC_TRUE; + + /* + * If we are not excluding any addresses then any AAAA + * will do. + */ + if (dns64->excluded == NULL) { + answer = ISC_TRUE; + for (i = 0; i < aaaaoklen; i++) + aaaaok[i] = ISC_TRUE; + goto done; + } + + i = 0; ok = 0; + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + if (aaaaok == NULL || !aaaaok[i]) { + + dns_rdataset_current(rdataset, &rdata); + memcpy(&in6.s6_addr, rdata.data, 16); + isc_netaddr_fromin6(&netaddr, &in6); + + result = dns_acl_match(&netaddr, NULL, + dns64->excluded, + env, &match, NULL); + if (result == ISC_R_SUCCESS && match <= 0) { + answer = ISC_TRUE; + if (aaaaok == NULL) + goto done; + aaaaok[i] = ISC_TRUE; + ok++; + } + } else + ok++; + i++; + } + /* + * Are all addresses ok? + */ + if (aaaaok != NULL && ok == aaaaoklen) + goto done; + } + + done: + if (!found && aaaaok != NULL) { + for (i = 0; i < aaaaoklen; i++) + aaaaok[i] = ISC_TRUE; + } + return (found ? answer : ISC_TRUE); +} diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c index 67a2c67..dc249b7 100644 --- a/lib/dns/dnssec.c +++ b/lib/dns/dnssec.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -16,7 +16,7 @@ */ /* - * $Id: dnssec.c,v 1.93.12.6 2009-06-22 23:47:18 tbox Exp $ + * $Id: dnssec.c,v 1.119 2010-01-13 23:48:59 tbox Exp $ */ /*! \file */ @@ -26,15 +26,18 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include +#include #include #include #include @@ -539,6 +542,59 @@ dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, return (result); } +static isc_boolean_t +key_active(dst_key_t *key) { + isc_result_t result; + isc_stdtime_t now, publish, active, revoke, inactive, delete; + isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE; + isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE; + isc_boolean_t delset = ISC_FALSE; + int major, minor; + + /* Is this an old-style key? */ + result = dst_key_getprivateformat(key, &major, &minor); + + /* + * Smart signing started with key format 1.3; prior to that, all + * keys are assumed active + */ + if (major == 1 && minor <= 2) + return (ISC_TRUE); + + isc_stdtime_get(&now); + + result = dst_key_gettime(key, DST_TIME_PUBLISH, &publish); + if (result == ISC_R_SUCCESS) + pubset = ISC_TRUE; + + result = dst_key_gettime(key, DST_TIME_ACTIVATE, &active); + if (result == ISC_R_SUCCESS) + actset = ISC_TRUE; + + result = dst_key_gettime(key, DST_TIME_REVOKE, &revoke); + if (result == ISC_R_SUCCESS) + revset = ISC_TRUE; + + result = dst_key_gettime(key, DST_TIME_INACTIVE, &inactive); + if (result == ISC_R_SUCCESS) + inactset = ISC_TRUE; + + result = dst_key_gettime(key, DST_TIME_DELETE, &delete); + if (result == ISC_R_SUCCESS) + delset = ISC_TRUE; + + if ((inactset && inactive <= now) || (delset && delete <= now)) + return (ISC_FALSE); + + if (revset && revoke <= now && pubset && publish <= now) + return (ISC_TRUE); + + if (actset && active <= now) + return (ISC_TRUE); + + return (ISC_FALSE); +} + #define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \ == DNS_KEYOWNER_ZONE) @@ -580,14 +636,70 @@ dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, directory, mctx, &keys[count]); + + /* + * If the key was revoked and the private file + * doesn't exist, maybe it was revoked internally + * by named. Try loading the unrevoked version. + */ if (result == ISC_R_FILENOTFOUND) { + isc_uint32_t flags; + flags = dst_key_flags(pubkey); + if ((flags & DNS_KEYFLAG_REVOKE) != 0) { + dst_key_setflags(pubkey, + flags & ~DNS_KEYFLAG_REVOKE); + result = dst_key_fromfile(dst_key_name(pubkey), + dst_key_id(pubkey), + dst_key_alg(pubkey), + DST_TYPE_PUBLIC| + DST_TYPE_PRIVATE, + directory, + mctx, &keys[count]); + if (result == ISC_R_SUCCESS && + dst_key_pubcompare(pubkey, keys[count], + ISC_FALSE)) { + dst_key_setflags(keys[count], flags); + } + dst_key_setflags(pubkey, flags); + } + } + + if (result != ISC_R_SUCCESS) { + char keybuf[DNS_NAME_FORMATSIZE]; + char algbuf[DNS_SECALG_FORMATSIZE]; + dns_name_format(dst_key_name(pubkey), keybuf, + sizeof(keybuf)); + dns_secalg_format(dst_key_alg(pubkey), algbuf, + sizeof(algbuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING, + "dns_dnssec_findzonekeys2: error " + "reading private key file %s/%s/%d: %s", + keybuf, algbuf, dst_key_id(pubkey), + isc_result_totext(result)); + } + + if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) { keys[count] = pubkey; pubkey = NULL; count++; goto next; } + if (result != ISC_R_SUCCESS) goto failure; + + /* + * If a key is marked inactive, skip it + */ + if (!key_active(keys[count])) { + dst_key_free(&keys[count]); + keys[count] = pubkey; + pubkey = NULL; + count++; + goto next; + } + if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) { /* We should never get here. */ dst_key_free(&keys[count]); @@ -951,3 +1063,691 @@ dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name, dst_key_free(&dstkey); return (ISC_FALSE); } + +isc_result_t +dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey, + dns_dnsseckey_t **dkp) +{ + isc_result_t result; + dns_dnsseckey_t *dk; + int major, minor; + + REQUIRE(dkp != NULL && *dkp == NULL); + dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t)); + if (dk == NULL) + return (ISC_R_NOMEMORY); + + dk->key = *dstkey; + *dstkey = NULL; + dk->force_publish = ISC_FALSE; + dk->force_sign = ISC_FALSE; + dk->hint_publish = ISC_FALSE; + dk->hint_sign = ISC_FALSE; + dk->hint_remove = ISC_FALSE; + dk->first_sign = ISC_FALSE; + dk->is_active = ISC_FALSE; + dk->prepublish = 0; + dk->source = dns_keysource_unknown; + dk->index = 0; + + /* KSK or ZSK? */ + dk->ksk = ISC_TF((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0); + + /* Is this an old-style key? */ + result = dst_key_getprivateformat(dk->key, &major, &minor); + + /* Smart signing started with key format 1.3 */ + dk->legacy = ISC_TF(major == 1 && minor <= 2); + + ISC_LINK_INIT(dk, link); + *dkp = dk; + return (ISC_R_SUCCESS); +} + +void +dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) { + dns_dnsseckey_t *dk; + + REQUIRE(dkp != NULL && *dkp != NULL); + dk = *dkp; + if (dk->key != NULL) + dst_key_free(&dk->key); + isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t)); + *dkp = NULL; +} + +static void +get_hints(dns_dnsseckey_t *key) { + isc_result_t result; + isc_stdtime_t now, publish, active, revoke, inactive, delete; + isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE; + isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE; + isc_boolean_t delset = ISC_FALSE; + + REQUIRE(key != NULL && key->key != NULL); + + isc_stdtime_get(&now); + + result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish); + if (result == ISC_R_SUCCESS) + pubset = ISC_TRUE; + + result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active); + if (result == ISC_R_SUCCESS) + actset = ISC_TRUE; + + result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke); + if (result == ISC_R_SUCCESS) + revset = ISC_TRUE; + + result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &inactive); + if (result == ISC_R_SUCCESS) + inactset = ISC_TRUE; + + result = dst_key_gettime(key->key, DST_TIME_DELETE, &delete); + if (result == ISC_R_SUCCESS) + delset = ISC_TRUE; + + /* Metadata says publish (but possibly not activate) */ + if (pubset && publish <= now) + key->hint_publish = ISC_TRUE; + + /* Metadata says activate (so we must also publish) */ + if (actset && active <= now) { + key->hint_sign = ISC_TRUE; + key->hint_publish = ISC_TRUE; + } + + /* + * Activation date is set (maybe in the future), but + * publication date isn't. Most likely the user wants to + * publish now and activate later. + */ + if (actset && !pubset) + key->hint_publish = ISC_TRUE; + + /* + * If activation date is in the future, make note of how far off + */ + if (key->hint_publish && actset && active > now) { + key->prepublish = active - now; + } + + /* + * Key has been marked inactive: we can continue publishing, + * but don't sign. + */ + if (key->hint_publish && inactset && inactive <= now) { + key->hint_sign = ISC_FALSE; + } + + /* + * Metadata says revoke. If the key is published, + * we *have to* sign with it per RFC5011--even if it was + * not active before. + * + * If it hasn't already been done, we should also revoke it now. + */ + if (key->hint_publish && (revset && revoke <= now)) { + isc_uint32_t flags; + key->hint_sign = ISC_TRUE; + flags = dst_key_flags(key->key); + if ((flags & DNS_KEYFLAG_REVOKE) == 0) { + flags |= DNS_KEYFLAG_REVOKE; + dst_key_setflags(key->key, flags); + } + } + + /* + * Metadata says delete, so don't publish this key or sign with it. + */ + if (delset && delete <= now) { + key->hint_publish = ISC_FALSE; + key->hint_sign = ISC_FALSE; + key->hint_remove = ISC_TRUE; + } +} + +/*% + * Get a list of DNSSEC keys from the key repository + */ +isc_result_t +dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory, + isc_mem_t *mctx, dns_dnsseckeylist_t *keylist) +{ + isc_result_t result = ISC_R_SUCCESS; + isc_boolean_t dir_open = ISC_FALSE; + dns_dnsseckeylist_t list; + isc_dir_t dir; + dns_dnsseckey_t *key = NULL; + dst_key_t *dstkey = NULL; + char namebuf[DNS_NAME_FORMATSIZE], *p; + isc_buffer_t b; + unsigned int len; + + REQUIRE(keylist != NULL); + ISC_LIST_INIT(list); + isc_dir_init(&dir); + + isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1); + RETERR(dns_name_totext(origin, ISC_FALSE, &b)); + len = isc_buffer_usedlength(&b); + namebuf[len] = '\0'; + + if (directory == NULL) + directory = "."; + RETERR(isc_dir_open(&dir, directory)); + dir_open = ISC_TRUE; + + while (isc_dir_read(&dir) == ISC_R_SUCCESS) { + if (dir.entry.name[0] == 'K' && + dir.entry.length > len + 1 && + dir.entry.name[len + 1] == '+' && + strncasecmp(dir.entry.name + 1, namebuf, len) == 0) { + p = strrchr(dir.entry.name, '.'); + if (p != NULL && strcmp(p, ".private") != 0) + continue; + + dstkey = NULL; + result = dst_key_fromnamedfile(dir.entry.name, + directory, + DST_TYPE_PUBLIC | + DST_TYPE_PRIVATE, + mctx, &dstkey); + + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_DNSSEC, + ISC_LOG_WARNING, + "dns_dnssec_findmatchingkeys: " + "error reading key file %s: %s", + dir.entry.name, + isc_result_totext(result)); + continue; + } + + RETERR(dns_dnsseckey_create(mctx, &dstkey, &key)); + key->source = dns_keysource_repository; + get_hints(key); + + if (key->legacy) { + dns_dnsseckey_destroy(mctx, &key); + } else { + ISC_LIST_APPEND(list, key, link); + key = NULL; + } + } + } + + if (!ISC_LIST_EMPTY(list)) + ISC_LIST_APPENDLIST(*keylist, list, link); + else + result = ISC_R_NOTFOUND; + + failure: + if (dir_open) + isc_dir_close(&dir); + INSIST(key == NULL); + while ((key = ISC_LIST_HEAD(list)) != NULL) { + ISC_LIST_UNLINK(list, key, link); + INSIST(key->key != NULL); + dst_key_free(&key->key); + dns_dnsseckey_destroy(mctx, &key); + } + if (dstkey != NULL) + dst_key_free(&dstkey); + return (result); +} + +/*% + * Add 'newkey' to 'keylist' if it's not already there. + * + * If 'savekeys' is ISC_TRUE, then we need to preserve all + * the keys in the keyset, regardless of whether they have + * metadata indicating they should be deactivated or removed. + */ +static void +addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey, + isc_boolean_t savekeys, isc_mem_t *mctx) +{ + dns_dnsseckey_t *key; + + /* Skip duplicates */ + for (key = ISC_LIST_HEAD(*keylist); + key != NULL; + key = ISC_LIST_NEXT(key, link)) { + if (dst_key_id(key->key) == dst_key_id(*newkey) && + dst_key_alg(key->key) == dst_key_alg(*newkey) && + dns_name_equal(dst_key_name(key->key), + dst_key_name(*newkey))) + break; + } + + if (key != NULL) { + /* + * Found a match. If the old key was only public and the + * new key is private, replace the old one; otherwise + * leave it. But either way, mark the key as having + * been found in the zone. + */ + if (dst_key_isprivate(key->key)) { + dst_key_free(newkey); + } else if (dst_key_isprivate(*newkey)) { + dst_key_free(&key->key); + key->key = *newkey; + } + + key->source = dns_keysource_zoneapex; + return; + } + + dns_dnsseckey_create(mctx, newkey, &key); + if (key->legacy || savekeys) { + key->force_publish = ISC_TRUE; + key->force_sign = dst_key_isprivate(key->key); + } + key->source = dns_keysource_zoneapex; + ISC_LIST_APPEND(*keylist, key, link); + *newkey = NULL; +} + + +/*% + * Mark all keys which signed the DNSKEY/SOA RRsets as "active", + * for future reference. + */ +static isc_result_t +mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) { + isc_result_t result = ISC_R_SUCCESS; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_t sigs; + dns_dnsseckey_t *key; + + REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs)); + + dns_rdataset_init(&sigs); + dns_rdataset_clone(rrsigs, &sigs); + for (key = ISC_LIST_HEAD(*keylist); + key != NULL; + key = ISC_LIST_NEXT(key, link)) { + isc_uint16_t keyid, sigid; + dns_secalg_t keyalg, sigalg; + keyid = dst_key_id(key->key); + keyalg = dst_key_alg(key->key); + + for (result = dns_rdataset_first(&sigs); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&sigs)) { + dns_rdata_rrsig_t sig; + + dns_rdata_reset(&rdata); + dns_rdataset_current(&sigs, &rdata); + result = dns_rdata_tostruct(&rdata, &sig, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + sigalg = sig.algorithm; + sigid = sig.keyid; + if (keyid == sigid && keyalg == sigalg) { + key->is_active = ISC_TRUE; + break; + } + } + } + + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + if (dns_rdataset_isassociated(&sigs)) + dns_rdataset_disassociate(&sigs); + return (result); +} + +/*% + * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'. + */ +isc_result_t +dns_dnssec_keylistfromrdataset(dns_name_t *origin, + const char *directory, isc_mem_t *mctx, + dns_rdataset_t *keyset, dns_rdataset_t *keysigs, + dns_rdataset_t *soasigs, isc_boolean_t savekeys, + isc_boolean_t public, + dns_dnsseckeylist_t *keylist) +{ + dns_rdataset_t keys; + dns_rdata_t rdata = DNS_RDATA_INIT; + dst_key_t *pubkey = NULL, *privkey = NULL; + isc_result_t result; + + REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset)); + + dns_rdataset_init(&keys); + + dns_rdataset_clone(keyset, &keys); + for (result = dns_rdataset_first(&keys); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&keys)) { + dns_rdata_reset(&rdata); + dns_rdataset_current(&keys, &rdata); + RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey)); + + if (!is_zone_key(pubkey) || + (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0) + goto skip; + + /* Corrupted .key file? */ + if (!dns_name_equal(origin, dst_key_name(pubkey))) + goto skip; + + if (public) { + addkey(keylist, &pubkey, savekeys, mctx); + goto skip; + } + + result = dst_key_fromfile(dst_key_name(pubkey), + dst_key_id(pubkey), + dst_key_alg(pubkey), + DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, + directory, mctx, &privkey); + + /* + * If the key was revoked and the private file + * doesn't exist, maybe it was revoked internally + * by named. Try loading the unrevoked version. + */ + if (result == ISC_R_FILENOTFOUND) { + isc_uint32_t flags; + flags = dst_key_flags(pubkey); + if ((flags & DNS_KEYFLAG_REVOKE) != 0) { + dst_key_setflags(pubkey, + flags & ~DNS_KEYFLAG_REVOKE); + result = dst_key_fromfile(dst_key_name(pubkey), + dst_key_id(pubkey), + dst_key_alg(pubkey), + DST_TYPE_PUBLIC| + DST_TYPE_PRIVATE, + directory, + mctx, &privkey); + if (result == ISC_R_SUCCESS && + dst_key_pubcompare(pubkey, privkey, + ISC_FALSE)) { + dst_key_setflags(privkey, flags); + } + dst_key_setflags(pubkey, flags); + } + } + + if (result != ISC_R_SUCCESS) { + char keybuf[DNS_NAME_FORMATSIZE]; + char algbuf[DNS_SECALG_FORMATSIZE]; + dns_name_format(dst_key_name(pubkey), keybuf, + sizeof(keybuf)); + dns_secalg_format(dst_key_alg(pubkey), algbuf, + sizeof(algbuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING, + "dns_dnssec_keylistfromrdataset: error " + "reading private key file %s/%s/%d: %s", + keybuf, algbuf, dst_key_id(pubkey), + isc_result_totext(result)); + } + + if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) { + addkey(keylist, &pubkey, savekeys, mctx); + goto skip; + } + RETERR(result); + + /* This should never happen. */ + if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0) + goto skip; + + addkey(keylist, &privkey, savekeys, mctx); + skip: + if (pubkey != NULL) + dst_key_free(&pubkey); + if (privkey != NULL) + dst_key_free(&privkey); + } + + if (result != ISC_R_NOMORE) + RETERR(result); + + if (keysigs != NULL && dns_rdataset_isassociated(keysigs)) + RETERR(mark_active_keys(keylist, keysigs)); + + if (soasigs != NULL && dns_rdataset_isassociated(soasigs)) + RETERR(mark_active_keys(keylist, soasigs)); + + result = ISC_R_SUCCESS; + + failure: + if (dns_rdataset_isassociated(&keys)) + dns_rdataset_disassociate(&keys); + if (pubkey != NULL) + dst_key_free(&pubkey); + if (privkey != NULL) + dst_key_free(&privkey); + return (result); +} + +static isc_result_t +make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize, + dns_rdata_t *target) +{ + isc_result_t result; + isc_buffer_t b; + isc_region_t r; + + isc_buffer_init(&b, buf, bufsize); + result = dst_key_todns(key, &b); + if (result != ISC_R_SUCCESS) + return (result); + + dns_rdata_reset(target); + isc_buffer_usedregion(&b, &r); + dns_rdata_fromregion(target, dst_key_class(key), + dns_rdatatype_dnskey, &r); + return (ISC_R_SUCCESS); +} + +static isc_result_t +publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin, + dns_ttl_t ttl, isc_mem_t *mctx, isc_boolean_t allzsk, + void (*report)(const char *, ...)) +{ + isc_result_t result; + dns_difftuple_t *tuple = NULL; + unsigned char buf[DST_KEY_MAXSIZE]; + dns_rdata_t dnskey = DNS_RDATA_INIT; + char alg[80]; + + dns_rdata_reset(&dnskey); + RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey)); + + dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg)); + report("Fetching %s %d/%s from key %s.", + key->ksk ? (allzsk ? "KSK/ZSK" : "KSK") : "ZSK", + dst_key_id(key->key), alg, + key->source == dns_keysource_user ? "file" : "repository"); + + if (key->prepublish && ttl > key->prepublish) { + char keystr[DST_KEY_FORMATSIZE]; + isc_stdtime_t now; + + dst_key_format(key->key, keystr, sizeof(keystr)); + report("Key %s: Delaying activation to match the DNSKEY TTL.\n", + keystr, ttl); + + isc_stdtime_get(&now); + dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl); + } + + /* publish key */ + RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl, + &dnskey, &tuple)); + dns_diff_appendminimal(diff, &tuple); + result = ISC_R_SUCCESS; + + failure: + return (result); +} + +static isc_result_t +remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin, + dns_ttl_t ttl, isc_mem_t *mctx, const char *reason, + void (*report)(const char *, ...)) +{ + isc_result_t result; + dns_difftuple_t *tuple = NULL; + unsigned char buf[DST_KEY_MAXSIZE]; + dns_rdata_t dnskey = DNS_RDATA_INIT; + char alg[80]; + + dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg)); + report("Removing %s key %d/%s from DNSKEY RRset.", + reason, dst_key_id(key->key), alg); + + RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey)); + RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, &dnskey, + &tuple)); + dns_diff_appendminimal(diff, &tuple); + result = ISC_R_SUCCESS; + + failure: + return (result); +} + +/* + * Update 'keys' with information from 'newkeys'. + * + * If 'removed' is not NULL, any keys that are being removed from + * the zone will be added to the list for post-removal processing. + */ +isc_result_t +dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys, + dns_dnsseckeylist_t *removed, dns_name_t *origin, + dns_ttl_t ttl, dns_diff_t *diff, isc_boolean_t allzsk, + isc_mem_t *mctx, void (*report)(const char *, ...)) +{ + isc_result_t result; + dns_dnsseckey_t *key, *key1, *key2, *next; + + /* + * First, look through the existing key list to find keys + * supplied from the command line which are not in the zone. + * Update the zone to include them. + */ + for (key = ISC_LIST_HEAD(*keys); + key != NULL; + key = ISC_LIST_NEXT(key, link)) { + if (key->source == dns_keysource_user && + (key->hint_publish || key->force_publish)) { + RETERR(publish_key(diff, key, origin, ttl, + mctx, allzsk, report)); + } + } + + /* + * Second, scan the list of newly found keys looking for matches + * with known keys, and update accordingly. + */ + for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) { + isc_boolean_t key_revoked = ISC_FALSE; + + next = ISC_LIST_NEXT(key1, link); + + for (key2 = ISC_LIST_HEAD(*keys); + key2 != NULL; + key2 = ISC_LIST_NEXT(key2, link)) { + if (dst_key_pubcompare(key1->key, key2->key, + ISC_TRUE)) { + int r1, r2; + r1 = dst_key_flags(key1->key) & + DNS_KEYFLAG_REVOKE; + r2 = dst_key_flags(key2->key) & + DNS_KEYFLAG_REVOKE; + key_revoked = ISC_TF(r1 != r2); + break; + } + } + + /* No match found in keys; add the new key. */ + if (key2 == NULL) { + dns_dnsseckey_t *next; + + next = ISC_LIST_NEXT(key1, link); + ISC_LIST_UNLINK(*newkeys, key1, link); + ISC_LIST_APPEND(*keys, key1, link); + + if (key1->source != dns_keysource_zoneapex && + (key1->hint_publish || key1->force_publish)) { + RETERR(publish_key(diff, key1, origin, ttl, + mctx, allzsk, report)); + if (key1->hint_sign || key1->force_sign) + key1->first_sign = ISC_TRUE; + } + + continue; + } + + /* Match found: remove or update it as needed */ + if (key1->hint_remove) { + RETERR(remove_key(diff, key2, origin, ttl, mctx, + "expired", report)); + ISC_LIST_UNLINK(*keys, key2, link); + if (removed != NULL) + ISC_LIST_APPEND(*removed, key2, link); + else + dns_dnsseckey_destroy(mctx, &key2); + } else if (key_revoked && + (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) { + + /* + * A previously valid key has been revoked. + * We need to remove the old version and pull + * in the new one. + */ + RETERR(remove_key(diff, key2, origin, ttl, mctx, + "revoked", report)); + ISC_LIST_UNLINK(*keys, key2, link); + if (removed != NULL) + ISC_LIST_APPEND(*removed, key2, link); + else + dns_dnsseckey_destroy(mctx, &key2); + + RETERR(publish_key(diff, key1, origin, ttl, + mctx, allzsk, report)); + ISC_LIST_UNLINK(*newkeys, key1, link); + ISC_LIST_APPEND(*keys, key1, link); + + /* + * XXX: The revoke flag is only defined for trust + * anchors. Setting the flag on a non-KSK is legal, + * but not defined in any RFC. It seems reasonable + * to treat it the same as a KSK: keep it in the + * zone, sign the DNSKEY set with it, but not + * sign other records with it. + */ + key1->ksk = ISC_TRUE; + continue; + } else { + if (!key2->is_active && + (key1->hint_sign || key1->force_sign)) + key2->first_sign = ISC_TRUE; + key2->hint_sign = key1->hint_sign; + key2->hint_publish = key1->hint_publish; + } + } + + /* Free any leftover keys in newkeys */ + while (!ISC_LIST_EMPTY(*newkeys)) { + key1 = ISC_LIST_HEAD(*newkeys); + ISC_LIST_UNLINK(*newkeys, key1, link); + dns_dnsseckey_destroy(mctx, &key1); + } + + result = ISC_R_SUCCESS; + + failure: + return (result); +} diff --git a/lib/dns/ds.c b/lib/dns/ds.c index 9cf5659..80e1503 100644 --- a/lib/dns/ds.c +++ b/lib/dns/ds.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ds.c,v 1.11 2007-06-19 23:47:16 tbox Exp $ */ +/* $Id: ds.c,v 1.13 2010-12-23 23:47:08 tbox Exp $ */ /*! \file */ @@ -38,6 +38,13 @@ #include +#ifdef HAVE_OPENSSL_GOST +#include +#include + +extern const EVP_MD * EVP_gost(void); +#endif + isc_result_t dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, unsigned int digest_type, unsigned char *buffer, @@ -49,6 +56,12 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, isc_region_t r; isc_buffer_t b; dns_rdata_ds_t ds; + isc_sha1_t sha1; + isc_sha256_t sha256; +#ifdef HAVE_OPENSSL_GOST + EVP_MD_CTX ctx; + const EVP_MD *md; +#endif REQUIRE(key != NULL); REQUIRE(key->type == dns_rdatatype_dnskey); @@ -63,8 +76,8 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, memset(buffer, 0, DNS_DS_BUFFERSIZE); isc_buffer_init(&b, buffer, DNS_DS_BUFFERSIZE); - if (digest_type == DNS_DSDIGEST_SHA1) { - isc_sha1_t sha1; + switch (digest_type) { + case DNS_DSDIGEST_SHA1: isc_sha1_init(&sha1); dns_name_toregion(name, &r); isc_sha1_update(&sha1, r.base, r.length); @@ -72,8 +85,33 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, INSIST(r.length >= 4); isc_sha1_update(&sha1, r.base, r.length); isc_sha1_final(&sha1, digest); - } else { - isc_sha256_t sha256; + break; +#ifdef HAVE_OPENSSL_GOST +#define CHECK(x) \ + if ((x) != 1) { \ + EVP_MD_CTX_cleanup(&ctx); \ + return (DST_R_OPENSSLFAILURE); \ + } + + case DNS_DSDIGEST_GOST: + md = EVP_gost(); + if (md == NULL) + return (DST_R_OPENSSLFAILURE); + EVP_MD_CTX_init(&ctx); + CHECK(EVP_DigestInit(&ctx, md)); + dns_name_toregion(name, &r); + CHECK(EVP_DigestUpdate(&ctx, + (const void *) r.base, + (size_t) r.length)); + dns_rdata_toregion(key, &r); + INSIST(r.length >= 4); + CHECK(EVP_DigestUpdate(&ctx, + (const void *) r.base, + (size_t) r.length)); + CHECK(EVP_DigestFinal(&ctx, digest, NULL)); + break; +#endif + default: isc_sha256_init(&sha256); dns_name_toregion(name, &r); isc_sha256_update(&sha256, r.base, r.length); @@ -81,6 +119,7 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, INSIST(r.length >= 4); isc_sha256_update(&sha256, r.base, r.length); isc_sha256_final(digest, &sha256); + break; } ds.mctx = NULL; @@ -89,8 +128,19 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, ds.algorithm = r.base[3]; ds.key_tag = dst_region_computeid(&r, ds.algorithm); ds.digest_type = digest_type; - ds.length = (digest_type == DNS_DSDIGEST_SHA1) ? - ISC_SHA1_DIGESTLENGTH : ISC_SHA256_DIGESTLENGTH; + switch (digest_type) { + case DNS_DSDIGEST_SHA1: + ds.length = ISC_SHA1_DIGESTLENGTH; + break; +#ifdef HAVE_OPENSSL_GOST + case DNS_DSDIGEST_GOST: + ds.length = ISC_GOST_DIGESTLENGTH; + break; +#endif + default: + ds.length = ISC_SHA256_DIGESTLENGTH; + break; + } ds.digest = digest; return (dns_rdata_fromstruct(rdata, key->rdclass, dns_rdatatype_ds, @@ -99,6 +149,12 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, isc_boolean_t dns_ds_digest_supported(unsigned int digest_type) { +#ifdef HAVE_OPENSSL_GOST + return (ISC_TF(digest_type == DNS_DSDIGEST_SHA1 || + digest_type == DNS_DSDIGEST_SHA256 || + digest_type == DNS_DSDIGEST_GOST)); +#else return (ISC_TF(digest_type == DNS_DSDIGEST_SHA1 || digest_type == DNS_DSDIGEST_SHA256)); +#endif } diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 97d2657..1ece312 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -31,7 +31,7 @@ /* * Principal Author: Brian Wellington - * $Id: dst_api.c,v 1.16.12.12 2010-12-09 01:12:55 marka Exp $ + * $Id: dst_api.c,v 1.57 2011-01-11 23:47:13 tbox Exp $ */ /*! \file */ @@ -39,6 +39,7 @@ #include #include +#include #include #include @@ -48,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -70,7 +72,9 @@ #define DST_AS_STR(t) ((t).value.as_textregion.base) static dst_func_t *dst_t_func[DST_MAX_ALGS]; +#ifdef BIND9 static isc_entropy_t *dst_entropy_pool = NULL; +#endif static unsigned int dst_entropy_flags = 0; static isc_boolean_t dst_initialized = ISC_FALSE; @@ -108,10 +112,11 @@ static isc_result_t frombuffer(dns_name_t *name, static isc_result_t algorithm_status(unsigned int alg); -static isc_result_t addsuffix(char *filename, unsigned int len, - const char *ofilename, const char *suffix); +static isc_result_t addsuffix(char *filename, int len, + const char *dirname, const char *ofilename, + const char *suffix); -#define RETERR(x) \ +#define RETERR(x) \ do { \ result = (x); \ if (result != ISC_R_SUCCESS) \ @@ -126,7 +131,7 @@ static isc_result_t addsuffix(char *filename, unsigned int len, return (_r); \ } while (0); \ -#ifdef OPENSSL +#if defined(OPENSSL) && defined(BIND9) static void * default_memalloc(void *arg, size_t size) { UNUSED(arg); @@ -144,14 +149,29 @@ default_memfree(void *arg, void *ptr) { isc_result_t dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { + return (dst_lib_init2(mctx, ectx, NULL, eflags)); +} + +isc_result_t +dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx, + const char *engine, unsigned int eflags) { isc_result_t result; - REQUIRE(mctx != NULL && ectx != NULL); + REQUIRE(mctx != NULL); +#ifdef BIND9 + REQUIRE(ectx != NULL); +#else + UNUSED(ectx); +#endif REQUIRE(dst_initialized == ISC_FALSE); +#ifndef OPENSSL + UNUSED(engine); +#endif + dst__memory_pool = NULL; -#ifdef OPENSSL +#if defined(OPENSSL) && defined(BIND9) UNUSED(mctx); /* * When using --with-openssl, there seems to be no good way of not @@ -166,11 +186,15 @@ dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { if (result != ISC_R_SUCCESS) return (result); isc_mem_setname(dst__memory_pool, "dst", NULL); +#ifndef OPENSSL_LEAKS isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE); +#endif #else isc_mem_attach(mctx, &dst__memory_pool); #endif +#ifdef BIND9 isc_entropy_attach(ectx, &dst_entropy_pool); +#endif dst_entropy_flags = eflags; dst_result_register(); @@ -183,7 +207,7 @@ dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384])); RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512])); #ifdef OPENSSL - RETERR(dst__openssl_init()); + RETERR(dst__openssl_init(engine)); RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5], DST_ALG_RSAMD5)); RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1], @@ -199,6 +223,9 @@ dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_NSEC3DSA])); #endif RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH])); +#ifdef HAVE_OPENSSL_GOST + RETERR(dst__opensslgost_init(&dst_t_func[DST_ALG_ECCGOST])); +#endif #endif /* OPENSSL */ #ifdef GSSAPI RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI])); @@ -207,6 +234,8 @@ dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { return (ISC_R_SUCCESS); out: + /* avoid immediate crash! */ + dst_initialized = ISC_TRUE; dst_lib_destroy(); return (result); } @@ -225,9 +254,10 @@ dst_lib_destroy(void) { #endif if (dst__memory_pool != NULL) isc_mem_detach(&dst__memory_pool); +#ifdef BIND9 if (dst_entropy_pool != NULL) isc_entropy_detach(&dst_entropy_pool); - +#endif } isc_boolean_t @@ -402,7 +432,7 @@ dst_key_fromfile(dns_name_t *name, dns_keytag_t id, return (result); key = NULL; - result = dst_key_fromnamedfile(filename, type, mctx, &key); + result = dst_key_fromnamedfile(filename, NULL, type, mctx, &key); if (result != ISC_R_SUCCESS) return (result); @@ -424,12 +454,11 @@ dst_key_fromfile(dns_name_t *name, dns_keytag_t id, } isc_result_t -dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, - dst_key_t **keyp) +dst_key_fromnamedfile(const char *filename, const char *dirname, + int type, isc_mem_t *mctx, dst_key_t **keyp) { isc_result_t result; dst_key_t *pubkey = NULL, *key = NULL; - dns_keytag_t id; char *newfilename = NULL; int newfilenamelen = 0; isc_lex_t *lex = NULL; @@ -440,11 +469,23 @@ dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, REQUIRE(mctx != NULL); REQUIRE(keyp != NULL && *keyp == NULL); + /* If an absolute path is specified, don't use the key directory */ +#ifndef WIN32 + if (filename[0] == '/') + dirname = NULL; +#else /* WIN32 */ + if (filename[0] == '/' || filename[0] == '\\') + dirname = NULL; +#endif + newfilenamelen = strlen(filename) + 5; + if (dirname != NULL) + newfilenamelen += strlen(dirname) + 1; newfilename = isc_mem_get(mctx, newfilenamelen); if (newfilename == NULL) return (ISC_R_NOMEMORY); - result = addsuffix(newfilename, newfilenamelen, filename, ".key"); + result = addsuffix(newfilename, newfilenamelen, + dirname, filename, ".key"); INSIST(result == ISC_R_SUCCESS); result = dst_key_read_public(newfilename, type, mctx, &pubkey); @@ -474,38 +515,43 @@ dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, key = get_key_struct(pubkey->key_name, pubkey->key_alg, pubkey->key_flags, pubkey->key_proto, 0, pubkey->key_class, mctx); - id = pubkey->key_id; - dst_key_free(&pubkey); - - if (key == NULL) + if (key == NULL) { + dst_key_free(&pubkey); return (ISC_R_NOMEMORY); + } if (key->func->parse == NULL) RETERR(DST_R_UNSUPPORTEDALG); newfilenamelen = strlen(filename) + 9; + if (dirname != NULL) + newfilenamelen += strlen(dirname) + 1; newfilename = isc_mem_get(mctx, newfilenamelen); if (newfilename == NULL) RETERR(ISC_R_NOMEMORY); - result = addsuffix(newfilename, newfilenamelen, filename, ".private"); + result = addsuffix(newfilename, newfilenamelen, + dirname, filename, ".private"); INSIST(result == ISC_R_SUCCESS); RETERR(isc_lex_create(mctx, 1500, &lex)); RETERR(isc_lex_openfile(lex, newfilename)); isc_mem_put(mctx, newfilename, newfilenamelen); - RETERR(key->func->parse(key, lex)); + RETERR(key->func->parse(key, lex, pubkey)); isc_lex_destroy(&lex); RETERR(computeid(key)); - if (id != key->key_id) + if (pubkey->key_id != key->key_id) RETERR(DST_R_INVALIDPRIVATEKEY); + dst_key_free(&pubkey); *keyp = key; return (ISC_R_SUCCESS); out: + if (pubkey != NULL) + dst_key_free(&pubkey); if (newfilename != NULL) isc_mem_put(mctx, newfilename, newfilenamelen); if (lex != NULL) @@ -640,7 +686,7 @@ dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) { RETERR(isc_lex_create(key->mctx, 1500, &lex)); RETERR(isc_lex_openbuffer(lex, buffer)); - RETERR(key->func->parse(key, lex)); + RETERR(key->func->parse(key, lex, NULL)); out: if (lex != NULL) isc_lex_destroy(&lex); @@ -657,9 +703,10 @@ dst_key_getgssctx(const dst_key_t *key) isc_result_t dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx, - dst_key_t **keyp) + dst_key_t **keyp, isc_region_t *intoken) { dst_key_t *key; + isc_result_t result; REQUIRE(gssctx != NULL); REQUIRE(keyp != NULL && *keyp == NULL); @@ -669,9 +716,21 @@ dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx, if (key == NULL) return (ISC_R_NOMEMORY); + if (intoken != NULL) { + /* + * Keep the token for use by external ssu rules. They may need + * to examine the PAC in the kerberos ticket. + */ + RETERR(isc_buffer_allocate(key->mctx, &key->key_tkeytoken, + intoken->length)); + RETERR(isc_buffer_copyregion(key->key_tkeytoken, intoken)); + } + key->keydata.gssctx = gssctx; *keyp = key; - return (ISC_R_SUCCESS); + result = ISC_R_SUCCESS; +out: + return result; } isc_result_t @@ -723,6 +782,18 @@ dst_key_generate(dns_name_t *name, unsigned int alg, dns_rdataclass_t rdclass, isc_mem_t *mctx, dst_key_t **keyp) { + return (dst_key_generate2(name, alg, bits, param, flags, protocol, + rdclass, mctx, keyp, NULL)); +} + +isc_result_t +dst_key_generate2(dns_name_t *name, unsigned int alg, + unsigned int bits, unsigned int param, + unsigned int flags, unsigned int protocol, + dns_rdataclass_t rdclass, + isc_mem_t *mctx, dst_key_t **keyp, + void (*callback)(int)) +{ dst_key_t *key; isc_result_t ret; @@ -748,7 +819,7 @@ dst_key_generate(dns_name_t *name, unsigned int alg, return (DST_R_UNSUPPORTEDALG); } - ret = key->func->generate(key, param); + ret = key->func->generate(key, param, callback); if (ret != ISC_R_SUCCESS) { dst_key_free(&key); return (ret); @@ -764,25 +835,185 @@ dst_key_generate(dns_name_t *name, unsigned int alg, return (ISC_R_SUCCESS); } -isc_boolean_t -dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) { +isc_result_t +dst_key_getnum(const dst_key_t *key, int type, isc_uint32_t *valuep) +{ + REQUIRE(VALID_KEY(key)); + REQUIRE(valuep != NULL); + REQUIRE(type <= DST_MAX_NUMERIC); + if (!key->numset[type]) + return (ISC_R_NOTFOUND); + *valuep = key->nums[type]; + return (ISC_R_SUCCESS); +} + +void +dst_key_setnum(dst_key_t *key, int type, isc_uint32_t value) +{ + REQUIRE(VALID_KEY(key)); + REQUIRE(type <= DST_MAX_NUMERIC); + key->nums[type] = value; + key->numset[type] = ISC_TRUE; +} + +void +dst_key_unsetnum(dst_key_t *key, int type) +{ + REQUIRE(VALID_KEY(key)); + REQUIRE(type <= DST_MAX_NUMERIC); + key->numset[type] = ISC_FALSE; +} + +isc_result_t +dst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep) { + REQUIRE(VALID_KEY(key)); + REQUIRE(timep != NULL); + REQUIRE(type <= DST_MAX_TIMES); + if (!key->timeset[type]) + return (ISC_R_NOTFOUND); + *timep = key->times[type]; + return (ISC_R_SUCCESS); +} + +void +dst_key_settime(dst_key_t *key, int type, isc_stdtime_t when) { + REQUIRE(VALID_KEY(key)); + REQUIRE(type <= DST_MAX_TIMES); + key->times[type] = when; + key->timeset[type] = ISC_TRUE; +} + +void +dst_key_unsettime(dst_key_t *key, int type) { + REQUIRE(VALID_KEY(key)); + REQUIRE(type <= DST_MAX_TIMES); + key->timeset[type] = ISC_FALSE; +} + +isc_result_t +dst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp) { + REQUIRE(VALID_KEY(key)); + REQUIRE(majorp != NULL); + REQUIRE(minorp != NULL); + *majorp = key->fmt_major; + *minorp = key->fmt_minor; + return (ISC_R_SUCCESS); +} + +void +dst_key_setprivateformat(dst_key_t *key, int major, int minor) { + REQUIRE(VALID_KEY(key)); + key->fmt_major = major; + key->fmt_minor = minor; +} + +static isc_boolean_t +comparekeys(const dst_key_t *key1, const dst_key_t *key2, + isc_boolean_t match_revoked_key, + isc_boolean_t (*compare)(const dst_key_t *key1, + const dst_key_t *key2)) +{ REQUIRE(dst_initialized == ISC_TRUE); REQUIRE(VALID_KEY(key1)); REQUIRE(VALID_KEY(key2)); if (key1 == key2) return (ISC_TRUE); + if (key1 == NULL || key2 == NULL) return (ISC_FALSE); - if (key1->key_alg == key2->key_alg && - key1->key_id == key2->key_id && - key1->func->compare != NULL && - key1->func->compare(key1, key2) == ISC_TRUE) - return (ISC_TRUE); + + if (key1->key_alg != key2->key_alg) + return (ISC_FALSE); + + /* + * For all algorithms except RSAMD5, revoking the key + * changes the key ID, increasing it by 128. If we want to + * be able to find matching keys even if one of them is the + * revoked version of the other one, then we need to check + * for that possibility. + */ + if (key1->key_id != key2->key_id) { + if (!match_revoked_key) + return (ISC_FALSE); + if (key1->key_alg == DST_ALG_RSAMD5) + return (ISC_FALSE); + if ((key1->key_flags & DNS_KEYFLAG_REVOKE) == + (key2->key_flags & DNS_KEYFLAG_REVOKE)) + return (ISC_FALSE); + if ((key1->key_flags & DNS_KEYFLAG_REVOKE) != 0 && + key1->key_id != ((key2->key_id + 128) & 0xffff)) + return (ISC_FALSE); + if ((key2->key_flags & DNS_KEYFLAG_REVOKE) != 0 && + key2->key_id != ((key1->key_id + 128) & 0xffff)) + return (ISC_FALSE); + } + + if (compare != NULL) + return (compare(key1, key2)); else return (ISC_FALSE); } + +/* + * Compares only the public portion of two keys, by converting them + * both to wire format and comparing the results. + */ +static isc_boolean_t +pub_compare(const dst_key_t *key1, const dst_key_t *key2) { + isc_result_t result; + unsigned char buf1[DST_KEY_MAXSIZE], buf2[DST_KEY_MAXSIZE]; + isc_buffer_t b1, b2; + isc_region_t r1, r2; + + isc_buffer_init(&b1, buf1, sizeof(buf1)); + result = dst_key_todns(key1, &b1); + if (result != ISC_R_SUCCESS) + return (ISC_FALSE); + /* Zero out flags. */ + buf1[0] = buf1[1] = 0; + if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) + isc_buffer_subtract(&b1, 2); + + isc_buffer_init(&b2, buf2, sizeof(buf2)); + result = dst_key_todns(key2, &b2); + if (result != ISC_R_SUCCESS) + return (ISC_FALSE); + /* Zero out flags. */ + buf2[0] = buf2[1] = 0; + if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) + isc_buffer_subtract(&b2, 2); + + isc_buffer_usedregion(&b1, &r1); + /* Remove extended flags. */ + if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) { + memmove(&buf1[4], &buf1[6], r1.length - 6); + r1.length -= 2; + } + + isc_buffer_usedregion(&b2, &r2); + /* Remove extended flags. */ + if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) { + memmove(&buf2[4], &buf2[6], r2.length - 6); + r2.length -= 2; + } + return (ISC_TF(isc_region_compare(&r1, &r2) == 0)); +} + +isc_boolean_t +dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) { + return (comparekeys(key1, key2, ISC_FALSE, key1->func->compare)); +} + +isc_boolean_t +dst_key_pubcompare(const dst_key_t *key1, const dst_key_t *key2, + isc_boolean_t match_revoked_key) +{ + return (comparekeys(key1, key2, match_revoked_key, pub_compare)); +} + + isc_boolean_t dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { REQUIRE(dst_initialized == ISC_TRUE); @@ -839,6 +1070,9 @@ dst_key_free(dst_key_t **keyp) { isc_mem_free(mctx, key->label); dns_name_free(key->key_name, mctx); isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); + if (key->key_tkeytoken) { + isc_buffer_free(&key->key_tkeytoken); + } memset(key, 0, sizeof(dst_key_t)); isc_mem_put(mctx, key, sizeof(dst_key_t)); *keyp = NULL; @@ -882,6 +1116,9 @@ dst_key_sigsize(const dst_key_t *key, unsigned int *n) { case DST_ALG_NSEC3DSA: *n = DNS_SIG_DSASIGSIZE; break; + case DST_ALG_ECCGOST: + *n = DNS_SIG_GOSTSIGSIZE; + break; case DST_ALG_HMACMD5: *n = 16; break; @@ -923,6 +1160,69 @@ dst_key_secretsize(const dst_key_t *key, unsigned int *n) { return (ISC_R_SUCCESS); } +/*% + * Set the flags on a key, then recompute the key ID + */ +isc_result_t +dst_key_setflags(dst_key_t *key, isc_uint32_t flags) { + REQUIRE(VALID_KEY(key)); + key->key_flags = flags; + return (computeid(key)); +} + +void +dst_key_format(const dst_key_t *key, char *cp, unsigned int size) { + char namestr[DNS_NAME_FORMATSIZE]; + char algstr[DNS_NAME_FORMATSIZE]; + + dns_name_format(dst_key_name(key), namestr, sizeof(namestr)); + dns_secalg_format((dns_secalg_t) dst_key_alg(key), algstr, + sizeof(algstr)); + snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key)); +} + +isc_result_t +dst_key_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) { + + REQUIRE(buffer != NULL && *buffer == NULL); + REQUIRE(length != NULL && *length == 0); + REQUIRE(VALID_KEY(key)); + + if (key->func->isprivate == NULL) + return (ISC_R_NOTIMPLEMENTED); + return (key->func->dump(key, mctx, buffer, length)); +} + +isc_result_t +dst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags, + unsigned int protocol, dns_rdataclass_t rdclass, + isc_mem_t *mctx, const char *keystr, dst_key_t **keyp) +{ + isc_result_t result; + dst_key_t *key; + + REQUIRE(dst_initialized == ISC_TRUE); + REQUIRE(keyp != NULL && *keyp == NULL); + + if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) + return (DST_R_UNSUPPORTEDALG); + + if (dst_t_func[alg]->restore == NULL) + return (ISC_R_NOTIMPLEMENTED); + + key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); + if (key == NULL) + return (ISC_R_NOMEMORY); + + result = (dst_t_func[alg]->restore)(key, keystr); + if (result == ISC_R_SUCCESS) + *keyp = key; + else + dst_key_free(&key); + + return (result); +} + /*** *** Static methods ***/ @@ -938,6 +1238,7 @@ get_key_struct(dns_name_t *name, unsigned int alg, { dst_key_t *key; isc_result_t result; + int i; key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t)); if (key == NULL) @@ -974,6 +1275,12 @@ get_key_struct(dns_name_t *name, unsigned int alg, key->key_size = bits; key->key_class = rdclass; key->func = dst_t_func[alg]; + key->fmt_major = 0; + key->fmt_minor = 0; + for (i = 0; i < (DST_MAX_TIMES + 1); i++) { + key->times[i] = 0; + key->timeset[i] = ISC_FALSE; + } return (key); } @@ -1046,7 +1353,7 @@ dst_key_read_public(const char *filename, int type, isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token))); isc_buffer_add(&b, strlen(DST_AS_STR(token))); ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname, - ISC_FALSE, NULL); + 0, NULL); if (ret != ISC_R_SUCCESS) goto cleanup; @@ -1116,6 +1423,7 @@ issymmetric(const dst_key_t *key) { case DST_ALG_DSA: case DST_ALG_NSEC3DSA: case DST_ALG_DH: + case DST_ALG_ECCGOST: return (ISC_FALSE); case DST_ALG_HMACMD5: case DST_ALG_GSSAPI: @@ -1126,6 +1434,55 @@ issymmetric(const dst_key_t *key) { } /*% + * Write key timing metadata to a file pointer, preceded by 'tag' + */ +static void +printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) { + isc_result_t result; +#ifdef ISC_PLATFORM_USETHREADS + char output[26]; /* Minimum buffer as per ctime_r() specification. */ +#else + const char *output; +#endif + isc_stdtime_t when; + time_t t; + char utc[sizeof("YYYYMMDDHHSSMM")]; + isc_buffer_t b; + isc_region_t r; + + result = dst_key_gettime(key, type, &when); + if (result == ISC_R_NOTFOUND) + return; + + /* time_t and isc_stdtime_t might be different sizes */ + t = when; +#ifdef ISC_PLATFORM_USETHREADS +#ifdef WIN32 + if (ctime_s(output, sizeof(output), &t) != 0) + goto error; +#else + if (ctime_r(&t, output) == NULL) + goto error; +#endif +#else + output = ctime(&t); +#endif + + isc_buffer_init(&b, utc, sizeof(utc)); + result = dns_time32_totext(when, &b); + if (result != ISC_R_SUCCESS) + goto error; + + isc_buffer_usedregion(&b, &r); + fprintf(stream, "%s: %.*s (%.*s)\n", tag, (int)r.length, r.base, + (int)strlen(output) - 1, output); + return; + + error: + fprintf(stream, "%s: (set, unable to display)\n", tag); +} + +/*% * Writes a public key to disk in DNS format. */ static isc_result_t @@ -1184,12 +1541,34 @@ write_public_key(const dst_key_t *key, int type, const char *directory) { (void)isc_fsaccess_set(filename, access); } - ret = dns_name_print(key->key_name, fp); - if (ret != ISC_R_SUCCESS) { - fclose(fp); - return (ret); + /* Write key information in comments */ + if ((type & DST_TYPE_KEY) == 0) { + fprintf(fp, "; This is a %s%s-signing key, keyid %d, for ", + (key->key_flags & DNS_KEYFLAG_REVOKE) != 0 ? + "revoked " : + "", + (key->key_flags & DNS_KEYFLAG_KSK) != 0 ? + "key" : + "zone", + key->key_id); + ret = dns_name_print(key->key_name, fp); + if (ret != ISC_R_SUCCESS) { + fclose(fp); + return (ret); + } + fputc('\n', fp); + + printtime(key, DST_TIME_CREATED, "; Created", fp); + printtime(key, DST_TIME_PUBLISH, "; Publish", fp); + printtime(key, DST_TIME_ACTIVATE, "; Activate", fp); + printtime(key, DST_TIME_REVOKE, "; Revoke", fp); + printtime(key, DST_TIME_INACTIVE, "; Inactive", fp); + printtime(key, DST_TIME_DELETE, "; Delete", fp); } + /* Now print the actual key */ + ret = dns_name_print(key->key_name, fp); + fprintf(fp, " "); isc_buffer_usedregion(&classb, &r); @@ -1317,15 +1696,16 @@ algorithm_status(unsigned int alg) { alg == DST_ALG_DSA || alg == DST_ALG_DH || alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA || alg == DST_ALG_NSEC3RSASHA1 || - alg == DST_ALG_RSASHA256 || alg == DST_ALG_RSASHA512) + alg == DST_ALG_RSASHA256 || alg == DST_ALG_RSASHA512 || + alg == DST_ALG_ECCGOST) return (DST_R_NOCRYPTO); #endif return (DST_R_UNSUPPORTEDALG); } static isc_result_t -addsuffix(char *filename, unsigned int len, const char *ofilename, - const char *suffix) +addsuffix(char *filename, int len, const char *odirname, + const char *ofilename, const char *suffix) { int olen = strlen(ofilename); int n; @@ -1337,27 +1717,42 @@ addsuffix(char *filename, unsigned int len, const char *ofilename, else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0) olen -= 4; - n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix); + if (odirname == NULL) + n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix); + else + n = snprintf(filename, len, "%s/%.*s%s", + odirname, olen, ofilename, suffix); if (n < 0) return (ISC_R_FAILURE); - if ((unsigned int)n >= len) + if (n >= len) return (ISC_R_NOSPACE); return (ISC_R_SUCCESS); } isc_result_t dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) { +#ifdef BIND9 unsigned int flags = dst_entropy_flags; if (len == 0) return (ISC_R_SUCCESS); if (pseudo) flags &= ~ISC_ENTROPY_GOODONLY; + else + flags |= ISC_ENTROPY_BLOCKING; return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags)); +#else + UNUSED(buf); + UNUSED(len); + UNUSED(pseudo); + + return (ISC_R_NOTIMPLEMENTED); +#endif } unsigned int dst__entropy_status(void) { +#ifdef BIND9 #ifdef GSSAPI unsigned int flags = dst_entropy_flags; isc_result_t ret; @@ -1376,4 +1771,12 @@ dst__entropy_status(void) { } #endif return (isc_entropy_status(dst_entropy_pool)); +#else + return (0); +#endif +} + +isc_buffer_t * +dst_key_tkeytoken(const dst_key_t *key) { + return (key->key_tkeytoken); } diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h index 01bf1f2..220b3da 100644 --- a/lib/dns/dst_internal.h +++ b/lib/dns/dst_internal.h @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 2000-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -29,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst_internal.h,v 1.11.120.3 2010-12-09 01:12:55 marka Exp $ */ +/* $Id: dst_internal.h,v 1.29 2011-01-11 23:47:13 tbox Exp $ */ #ifndef DST_DST_INTERNAL_H #define DST_DST_INTERNAL_H 1 @@ -44,9 +44,12 @@ #include #include #include +#include #include #include +#include + #include #ifdef OPENSSL @@ -60,8 +63,8 @@ ISC_LANG_BEGINDECLS -#define KEY_MAGIC ISC_MAGIC('D','S','T','K') -#define CTX_MAGIC ISC_MAGIC('D','S','T','C') +#define KEY_MAGIC ISC_MAGIC('D','S','T','K') +#define CTX_MAGIC ISC_MAGIC('D','S','T','C') #define VALID_KEY(x) ISC_MAGIC_VALID(x, KEY_MAGIC) #define VALID_CTX(x) ISC_MAGIC_VALID(x, CTX_MAGIC) @@ -74,7 +77,7 @@ extern isc_mem_t *dst__memory_pool; typedef struct dst_func dst_func_t; -typedef struct dst_hmacmd5_key dst_hmacmd5_key_t; +typedef struct dst_hmacmd5_key dst_hmacmd5_key_t; typedef struct dst_hmacsha1_key dst_hmacsha1_key_t; typedef struct dst_hmacsha224_key dst_hmacsha224_key_t; typedef struct dst_hmacsha256_key dst_hmacsha256_key_t; @@ -115,7 +118,17 @@ struct dst_key { dst_hmacsha512_key_t *hmacsha512; } keydata; /*%< pointer to key in crypto pkg fmt */ - dst_func_t * func; /*%< crypto package specific functions */ + + isc_stdtime_t times[DST_MAX_TIMES + 1]; /*%< timing metadata */ + isc_boolean_t timeset[DST_MAX_TIMES + 1]; /*%< data set? */ + isc_stdtime_t nums[DST_MAX_NUMERIC + 1]; /*%< numeric metadata */ + isc_boolean_t numset[DST_MAX_NUMERIC + 1]; /*%< data set? */ + + int fmt_major; /*%< private key format, major version */ + int fmt_minor; /*%< private key format, minor version */ + + dst_func_t * func; /*%< crypto package specific functions */ + isc_buffer_t *key_tkeytoken; /*%< TKEY token data */ }; struct dst_context { @@ -160,7 +173,8 @@ struct dst_func { isc_boolean_t (*compare)(const dst_key_t *key1, const dst_key_t *key2); isc_boolean_t (*paramcompare)(const dst_key_t *key1, const dst_key_t *key2); - isc_result_t (*generate)(dst_key_t *key, int parms); + isc_result_t (*generate)(dst_key_t *key, int parms, + void (*callback)(int)); isc_boolean_t (*isprivate)(const dst_key_t *key); void (*destroy)(dst_key_t *key); @@ -168,19 +182,24 @@ struct dst_func { isc_result_t (*todns)(const dst_key_t *key, isc_buffer_t *data); isc_result_t (*fromdns)(dst_key_t *key, isc_buffer_t *data); isc_result_t (*tofile)(const dst_key_t *key, const char *directory); - isc_result_t (*parse)(dst_key_t *key, isc_lex_t *lexer); + isc_result_t (*parse)(dst_key_t *key, + isc_lex_t *lexer, + dst_key_t *pub); /* cleanup */ void (*cleanup)(void); isc_result_t (*fromlabel)(dst_key_t *key, const char *engine, const char *label, const char *pin); + isc_result_t (*dump)(dst_key_t *key, isc_mem_t *mctx, char **buffer, + int *length); + isc_result_t (*restore)(dst_key_t *key, const char *keystr); }; /*% * Initializers */ -isc_result_t dst__openssl_init(void); +isc_result_t dst__openssl_init(const char *engine); isc_result_t dst__hmacmd5_init(struct dst_func **funcp); isc_result_t dst__hmacsha1_init(struct dst_func **funcp); @@ -193,6 +212,9 @@ isc_result_t dst__opensslrsa_init(struct dst_func **funcp, isc_result_t dst__openssldsa_init(struct dst_func **funcp); isc_result_t dst__openssldh_init(struct dst_func **funcp); isc_result_t dst__gssapi_init(struct dst_func **funcp); +#ifdef HAVE_OPENSSL_GOST +isc_result_t dst__opensslgost_init(struct dst_func **funcp); +#endif /*% * Destructors diff --git a/lib/dns/dst_openssl.h b/lib/dns/dst_openssl.h index a095d45..781085b 100644 --- a/lib/dns/dst_openssl.h +++ b/lib/dns/dst_openssl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst_openssl.h,v 1.7 2008-04-01 23:47:10 tbox Exp $ */ +/* $Id: dst_openssl.h,v 1.9 2009-10-06 04:40:14 tbox Exp $ */ #ifndef DST_OPENSSL_H #define DST_OPENSSL_H 1 @@ -29,10 +29,7 @@ isc_result_t dst__openssl_toresult(isc_result_t fallback); ENGINE * -dst__openssl_getengine(const char *name); - -isc_result_t -dst__openssl_setdefault(const char *name); +dst__openssl_getengine(const char *engine); ISC_LANG_ENDDECLS diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c index 37264be..4d7d784 100644 --- a/lib/dns/dst_parse.c +++ b/lib/dns/dst_parse.c @@ -31,7 +31,7 @@ /*% * Principal Author: Brian Wellington - * $Id: dst_parse.c,v 1.14.120.6 2010-01-15 19:38:53 each Exp $ + * $Id: dst_parse.c,v 1.27 2010-12-23 04:07:58 marka Exp $ */ #include @@ -41,9 +41,12 @@ #include #include #include +#include #include #include +#include + #include "dst_internal.h" #include "dst_parse.h" #include "dst/result.h" @@ -53,6 +56,25 @@ #define PRIVATE_KEY_STR "Private-key-format:" #define ALGORITHM_STR "Algorithm:" +#define TIMING_NTAGS (DST_MAX_TIMES + 1) +static const char *timetags[TIMING_NTAGS] = { + "Created:", + "Publish:", + "Activate:", + "Revoke:", + "Inactive:", + "Delete:", + "DSPublish:" +}; + +#define NUMERIC_NTAGS (DST_MAX_NUMERIC + 1) +static const char *numerictags[NUMERIC_NTAGS] = { + "Predecessor:", + "Successor:", + "MaxTTL:", + "RollPeriod:" +}; + struct parse_map { const int value; const char *tag; @@ -82,6 +104,8 @@ static struct parse_map map[] = { {TAG_DSA_PRIVATE, "Private_value(x):"}, {TAG_DSA_PUBLIC, "Public_value(y):"}, + {TAG_GOST_PRIVASN1, "GostAsn1:"}, + {TAG_HMACMD5_KEY, "Key:"}, {TAG_HMACMD5_BITS, "Bits:"}, @@ -107,13 +131,12 @@ static int find_value(const char *s, const unsigned int alg) { int i; - for (i = 0; ; i++) { - if (map[i].tag == NULL) - return (-1); - else if (strcasecmp(s, map[i].tag) == 0 && - TAG_ALG(map[i].value) == alg) + for (i = 0; map[i].tag != NULL; i++) { + if (strcasecmp(s, map[i].tag) == 0 && + (TAG_ALG(map[i].value) == alg)) return (map[i].value); } + return (-1); } static const char * @@ -129,6 +152,28 @@ find_tag(const int value) { } static int +find_metadata(const char *s, const char *tags[], int ntags) { + int i; + + for (i = 0; i < ntags; i++) { + if (strcasecmp(s, tags[i]) == 0) + return (i); + } + + return (-1); +} + +static int +find_timedata(const char *s) { + return (find_metadata(s, timetags, TIMING_NTAGS)); +} + +static int +find_numericdata(const char *s) { + return (find_metadata(s, numerictags, NUMERIC_NTAGS)); +} + +static int check_rsa(const dst_private_t *priv) { int i, j; isc_boolean_t have[RSA_NTAGS]; @@ -197,6 +242,15 @@ check_dsa(const dst_private_t *priv) { } static int +check_gost(const dst_private_t *priv) { + if (priv->nelements != GOST_NTAGS) + return (-1); + if (priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 0)) + return (-1); + return (0); +} + +static int check_hmac_md5(const dst_private_t *priv, isc_boolean_t old) { int i, j; @@ -253,6 +307,8 @@ check_data(const dst_private_t *priv, const unsigned int alg, return (check_dh(priv)); case DST_ALG_DSA: return (check_dsa(priv)); + case DST_ALG_ECCGOST: + return (check_gost(priv)); case DST_ALG_HMACMD5: return (check_hmac_md5(priv, old)); case DST_ALG_HMACSHA1: @@ -285,7 +341,7 @@ dst__privstruct_free(dst_private_t *priv, isc_mem_t *mctx) { priv->nelements = 0; } -int +isc_result_t dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, isc_mem_t *mctx, dst_private_t *priv) { @@ -294,6 +350,7 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, isc_token_t token; unsigned char *data = NULL; unsigned int opt = ISC_LEXOPT_EOL; + isc_stdtime_t when; isc_result_t ret; REQUIRE(priv != NULL); @@ -341,13 +398,16 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, goto fail; } - if (major > MAJOR_VERSION || - (major == MAJOR_VERSION && minor > MINOR_VERSION)) - { + if (major > DST_MAJOR_VERSION) { ret = DST_R_INVALIDPRIVATEKEY; goto fail; } + /* + * Store the private key format version number + */ + dst_key_setprivateformat(key, major, minor); + READLINE(lex, opt, &token); /* @@ -377,7 +437,6 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, for (n = 0; n < MAXFIELDS; n++) { int tag; isc_region_t r; - do { ret = isc_lex_gettoken(lex, opt, &token); if (ret == ISC_R_EOF) @@ -391,11 +450,50 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, goto fail; } + /* Numeric metadata */ + tag = find_numericdata(DST_AS_STR(token)); + if (tag >= 0) { + INSIST(tag < NUMERIC_NTAGS); + + NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token); + if (token.type != isc_tokentype_number) { + ret = DST_R_INVALIDPRIVATEKEY; + goto fail; + } + + dst_key_setnum(key, tag, token.value.as_ulong); + goto next; + } + + /* Timing metadata */ + tag = find_timedata(DST_AS_STR(token)); + if (tag >= 0) { + INSIST(tag < TIMING_NTAGS); + + NEXTTOKEN(lex, opt, &token); + if (token.type != isc_tokentype_string) { + ret = DST_R_INVALIDPRIVATEKEY; + goto fail; + } + + ret = dns_time32_fromtext(DST_AS_STR(token), &when); + if (ret != ISC_R_SUCCESS) + goto fail; + + dst_key_settime(key, tag, when); + + goto next; + } + + /* Key data */ tag = find_value(DST_AS_STR(token), alg); - if (tag < 0 || TAG_ALG(tag) != alg) { + if (tag < 0 && minor > DST_MINOR_VERSION) + goto next; + else if (tag < 0) { ret = DST_R_INVALIDPRIVATEKEY; goto fail; } + priv->elements[n].tag = tag; data = (unsigned char *) isc_mem_get(mctx, MAXFIELDSIZE); @@ -406,23 +504,23 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, ret = isc_base64_tobuffer(lex, &b, -1); if (ret != ISC_R_SUCCESS) goto fail; + isc_buffer_usedregion(&b, &r); priv->elements[n].length = r.length; priv->elements[n].data = r.base; + priv->nelements++; + next: READLINE(lex, opt, &token); data = NULL; } done: - priv->nelements = n; - if (check_data(priv, alg, ISC_TRUE) < 0) goto fail; return (ISC_R_SUCCESS); fail: - priv->nelements = n; dst__privstruct_free(priv, mctx); if (data != NULL) isc_mem_put(mctx, data, MAXFIELDSIZE); @@ -430,17 +528,21 @@ fail: return (ret); } -int +isc_result_t dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, const char *directory) { FILE *fp; int ret, i; - isc_result_t iret; + isc_result_t result; char filename[ISC_DIR_NAMEMAX]; char buffer[MAXFIELDSIZE * 2]; - isc_buffer_t b; isc_fsaccess_t access; + isc_stdtime_t when; + isc_uint32_t value; + isc_buffer_t b; + isc_region_t r; + int major, minor; REQUIRE(priv != NULL); @@ -461,11 +563,17 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, &access); (void)isc_fsaccess_set(filename, access); + dst_key_getprivateformat(key, &major, &minor); + if (major == 0 && minor == 0) { + major = DST_MAJOR_VERSION; + minor = DST_MINOR_VERSION; + } + /* XXXDCL return value should be checked for full filesystem */ - fprintf(fp, "%s v%d.%d\n", PRIVATE_KEY_STR, MAJOR_VERSION, - MINOR_VERSION); + fprintf(fp, "%s v%d.%d\n", PRIVATE_KEY_STR, major, minor); fprintf(fp, "%s %d ", ALGORITHM_STR, dst_key_alg(key)); + /* XXXVIX this switch statement is too sparse to gen a jump table. */ switch (dst_key_alg(key)) { case DST_ALG_RSAMD5: @@ -480,18 +588,21 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, case DST_ALG_RSASHA1: fprintf(fp, "(RSASHA1)\n"); break; - case DST_ALG_NSEC3DSA: - fprintf(fp, "(NSEC3DSA)\n"); - break; case DST_ALG_NSEC3RSASHA1: fprintf(fp, "(NSEC3RSASHA1)\n"); break; + case DST_ALG_NSEC3DSA: + fprintf(fp, "(NSEC3DSA)\n"); + break; case DST_ALG_RSASHA256: fprintf(fp, "(RSASHA256)\n"); break; case DST_ALG_RSASHA512: fprintf(fp, "(RSASHA512)\n"); break; + case DST_ALG_ECCGOST: + fprintf(fp, "(ECC-GOST)\n"); + break; case DST_ALG_HMACMD5: fprintf(fp, "(HMAC_MD5)\n"); break; @@ -516,8 +627,6 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, } for (i = 0; i < priv->nelements; i++) { - isc_buffer_t b; - isc_region_t r; const char *s; s = find_tag(priv->elements[i].tag); @@ -525,8 +634,8 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, r.base = priv->elements[i].data; r.length = priv->elements[i].length; isc_buffer_init(&b, buffer, sizeof(buffer)); - iret = isc_base64_totext(&r, sizeof(buffer), "", &b); - if (iret != ISC_R_SUCCESS) { + result = isc_base64_totext(&r, sizeof(buffer), "", &b); + if (result != ISC_R_SUCCESS) { fclose(fp); return (DST_R_INVALIDPRIVATEKEY); } @@ -537,10 +646,36 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, fprintf(fp, "\n"); } + /* Add the metadata tags */ + if (major > 1 || (major == 1 && minor >= 3)) { + for (i = 0; i < NUMERIC_NTAGS; i++) { + result = dst_key_getnum(key, i, &value); + if (result != ISC_R_SUCCESS) + continue; + fprintf(fp, "%s %u\n", numerictags[i], value); + } + for (i = 0; i < TIMING_NTAGS; i++) { + result = dst_key_gettime(key, i, &when); + if (result != ISC_R_SUCCESS) + continue; + + isc_buffer_init(&b, buffer, sizeof(buffer)); + result = dns_time32_totext(when, &b); + if (result != ISC_R_SUCCESS) + continue; + + isc_buffer_usedregion(&b, &r); + + fprintf(fp, "%s ", timetags[i]); + isc_util_fwrite(r.base, 1, r.length, fp); + fprintf(fp, "\n"); + } + } + fflush(fp); - iret = ferror(fp) ? DST_R_WRITEERROR : ISC_R_SUCCESS; + result = ferror(fp) ? DST_R_WRITEERROR : ISC_R_SUCCESS; fclose(fp); - return (iret); + return (result); } /*! \file */ diff --git a/lib/dns/dst_parse.h b/lib/dns/dst_parse.h index 11e2b33..d1034ce 100644 --- a/lib/dns/dst_parse.h +++ b/lib/dns/dst_parse.h @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 2000-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -29,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst_parse.h,v 1.11 2008-05-15 00:50:26 each Exp $ */ +/* $Id: dst_parse.h,v 1.17 2010-12-23 23:47:08 tbox Exp $ */ /*! \file */ #ifndef DST_DST_PARSE_H @@ -39,11 +39,13 @@ #include -#define MAJOR_VERSION 1 -#define MINOR_VERSION 2 - #define MAXFIELDSIZE 512 -#define MAXFIELDS 12 + +/* + * Maximum number of fields in a private file is 18 (12 algorithm- + * specific fields for RSA, plus 6 generic fields). + */ +#define MAXFIELDS 12+6 #define TAG_SHIFT 4 #define TAG_ALG(tag) ((unsigned int)(tag) >> TAG_SHIFT) @@ -76,6 +78,9 @@ #define TAG_DSA_PRIVATE ((DST_ALG_DSA << TAG_SHIFT) + 3) #define TAG_DSA_PUBLIC ((DST_ALG_DSA << TAG_SHIFT) + 4) +#define GOST_NTAGS 1 +#define TAG_GOST_PRIVASN1 ((DST_ALG_ECCGOST << TAG_SHIFT) + 0) + #define OLD_HMACMD5_NTAGS 1 #define HMACMD5_NTAGS 2 #define TAG_HMACMD5_KEY ((DST_ALG_HMACMD5 << TAG_SHIFT) + 0) @@ -121,11 +126,11 @@ ISC_LANG_BEGINDECLS void dst__privstruct_free(dst_private_t *priv, isc_mem_t *mctx); -int +isc_result_t dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, isc_mem_t *mctx, dst_private_t *priv); -int +isc_result_t dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, const char *directory); diff --git a/lib/dns/ecdb.c b/lib/dns/ecdb.c new file mode 100644 index 0000000..d98a3eb --- /dev/null +++ b/lib/dns/ecdb.c @@ -0,0 +1,810 @@ +/* + * Copyright (C) 2009-2011 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: ecdb.c,v 1.8 2011-01-14 00:51:43 tbox Exp $ */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define ECDB_MAGIC ISC_MAGIC('E', 'C', 'D', 'B') +#define VALID_ECDB(db) ((db) != NULL && \ + (db)->common.impmagic == ECDB_MAGIC) + +#define ECDBNODE_MAGIC ISC_MAGIC('E', 'C', 'D', 'N') +#define VALID_ECDBNODE(ecdbn) ISC_MAGIC_VALID(ecdbn, ECDBNODE_MAGIC) + +#if DNS_RDATASET_FIXED +#error "Fixed rdataset isn't supported in this implementation" +#endif + +/*% + * The 'ephemeral' cache DB (ecdb) implementation. An ecdb just provides + * temporary storage for ongoing name resolution with the common DB interfaces. + * It actually doesn't cache anything. The implementation expects any stored + * data is released within a short period, and does not care about the + * scalability in terms of the number of nodes. + */ + +typedef struct dns_ecdb { + /* Unlocked */ + dns_db_t common; + isc_mutex_t lock; + + /* Locked */ + unsigned int references; + ISC_LIST(struct dns_ecdbnode) nodes; +} dns_ecdb_t; + +typedef struct dns_ecdbnode { + /* Unlocked */ + unsigned int magic; + isc_mutex_t lock; + dns_ecdb_t *ecdb; + dns_name_t name; + ISC_LINK(struct dns_ecdbnode) link; + + /* Locked */ + ISC_LIST(struct rdatasetheader) rdatasets; + unsigned int references; +} dns_ecdbnode_t; + +typedef struct rdatasetheader { + dns_rdatatype_t type; + dns_ttl_t ttl; + dns_trust_t trust; + dns_rdatatype_t covers; + unsigned int attributes; + + ISC_LINK(struct rdatasetheader) link; +} rdatasetheader_t; + +/* Copied from rbtdb.c */ +#define RDATASET_ATTR_NXDOMAIN 0x0010 +#define NXDOMAIN(header) \ + (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0) + +static isc_result_t dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin, + dns_dbtype_t type, + dns_rdataclass_t rdclass, + unsigned int argc, char *argv[], + void *driverarg, dns_db_t **dbp); + +static void rdataset_disassociate(dns_rdataset_t *rdataset); +static isc_result_t rdataset_first(dns_rdataset_t *rdataset); +static isc_result_t rdataset_next(dns_rdataset_t *rdataset); +static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata); +static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target); +static unsigned int rdataset_count(dns_rdataset_t *rdataset); +static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust); + +static dns_rdatasetmethods_t rdataset_methods = { + rdataset_disassociate, + rdataset_first, + rdataset_next, + rdataset_current, + rdataset_clone, + rdataset_count, + NULL, /* addnoqname */ + NULL, /* getnoqname */ + NULL, /* addclosest */ + NULL, /* getclosest */ + NULL, /* getadditional */ + NULL, /* setadditional */ + NULL, /* putadditional */ + rdataset_settrust, /* settrust */ + NULL /* expire */ +}; + +typedef struct ecdb_rdatasetiter { + dns_rdatasetiter_t common; + rdatasetheader_t *current; +} ecdb_rdatasetiter_t; + +static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp); +static isc_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator); +static isc_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator); +static void rdatasetiter_current(dns_rdatasetiter_t *iterator, + dns_rdataset_t *rdataset); + +static dns_rdatasetitermethods_t rdatasetiter_methods = { + rdatasetiter_destroy, + rdatasetiter_first, + rdatasetiter_next, + rdatasetiter_current +}; + +isc_result_t +dns_ecdb_register(isc_mem_t *mctx, dns_dbimplementation_t **dbimp) { + REQUIRE(mctx != NULL); + REQUIRE(dbimp != NULL && *dbimp == NULL); + + return (dns_db_register("ecdb", dns_ecdb_create, NULL, mctx, dbimp)); +} + +void +dns_ecdb_unregister(dns_dbimplementation_t **dbimp) { + REQUIRE(dbimp != NULL && *dbimp != NULL); + + dns_db_unregister(dbimp); +} + +/*% + * DB routines + */ + +static void +attach(dns_db_t *source, dns_db_t **targetp) { + dns_ecdb_t *ecdb = (dns_ecdb_t *)source; + + REQUIRE(VALID_ECDB(ecdb)); + REQUIRE(targetp != NULL && *targetp == NULL); + + LOCK(&ecdb->lock); + ecdb->references++; + UNLOCK(&ecdb->lock); + + *targetp = source; +} + +static void +destroy_ecdb(dns_ecdb_t **ecdbp) { + dns_ecdb_t *ecdb = *ecdbp; + isc_mem_t *mctx = ecdb->common.mctx; + + if (dns_name_dynamic(&ecdb->common.origin)) + dns_name_free(&ecdb->common.origin, mctx); + + DESTROYLOCK(&ecdb->lock); + + ecdb->common.impmagic = 0; + ecdb->common.magic = 0; + + isc_mem_putanddetach(&mctx, ecdb, sizeof(*ecdb)); + + *ecdbp = NULL; +} + +static void +detach(dns_db_t **dbp) { + dns_ecdb_t *ecdb; + isc_boolean_t need_destroy = ISC_FALSE; + + REQUIRE(dbp != NULL); + ecdb = (dns_ecdb_t *)*dbp; + REQUIRE(VALID_ECDB(ecdb)); + + LOCK(&ecdb->lock); + ecdb->references--; + if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes)) + need_destroy = ISC_TRUE; + UNLOCK(&ecdb->lock); + + if (need_destroy) + destroy_ecdb(&ecdb); + + *dbp = NULL; +} + +static void +attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) { + dns_ecdb_t *ecdb = (dns_ecdb_t *)db; + dns_ecdbnode_t *node = (dns_ecdbnode_t *)source; + + REQUIRE(VALID_ECDB(ecdb)); + REQUIRE(VALID_ECDBNODE(node)); + REQUIRE(targetp != NULL && *targetp == NULL); + + LOCK(&node->lock); + INSIST(node->references > 0); + node->references++; + INSIST(node->references != 0); /* Catch overflow. */ + UNLOCK(&node->lock); + + *targetp = node; +} + +static void +destroynode(dns_ecdbnode_t *node) { + isc_mem_t *mctx; + dns_ecdb_t *ecdb = node->ecdb; + isc_boolean_t need_destroydb = ISC_FALSE; + rdatasetheader_t *header; + + mctx = ecdb->common.mctx; + + LOCK(&ecdb->lock); + ISC_LIST_UNLINK(ecdb->nodes, node, link); + if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes)) + need_destroydb = ISC_TRUE; + UNLOCK(&ecdb->lock); + + dns_name_free(&node->name, mctx); + + while ((header = ISC_LIST_HEAD(node->rdatasets)) != NULL) { + unsigned int headersize; + + ISC_LIST_UNLINK(node->rdatasets, header, link); + headersize = + dns_rdataslab_size((unsigned char *)header, + sizeof(*header)); + isc_mem_put(mctx, header, headersize); + } + + DESTROYLOCK(&node->lock); + + node->magic = 0; + isc_mem_put(mctx, node, sizeof(*node)); + + if (need_destroydb) + destroy_ecdb(&ecdb); +} + +static void +detachnode(dns_db_t *db, dns_dbnode_t **nodep) { + dns_ecdb_t *ecdb = (dns_ecdb_t *)db; + dns_ecdbnode_t *node; + isc_boolean_t need_destroy = ISC_FALSE; + + REQUIRE(VALID_ECDB(ecdb)); + REQUIRE(nodep != NULL); + node = (dns_ecdbnode_t *)*nodep; + REQUIRE(VALID_ECDBNODE(node)); + + UNUSED(ecdb); /* in case REQUIRE() is empty */ + + LOCK(&node->lock); + INSIST(node->references > 0); + node->references--; + if (node->references == 0) + need_destroy = ISC_TRUE; + UNLOCK(&node->lock); + + if (need_destroy) + destroynode(node); + + *nodep = NULL; +} + +static isc_result_t +find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, + dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, + dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset) +{ + dns_ecdb_t *ecdb = (dns_ecdb_t *)db; + + REQUIRE(VALID_ECDB(ecdb)); + + UNUSED(name); + UNUSED(version); + UNUSED(type); + UNUSED(options); + UNUSED(now); + UNUSED(nodep); + UNUSED(foundname); + UNUSED(rdataset); + UNUSED(sigrdataset); + + return (ISC_R_NOTFOUND); +} + +static isc_result_t +findzonecut(dns_db_t *db, dns_name_t *name, + unsigned int options, isc_stdtime_t now, + dns_dbnode_t **nodep, dns_name_t *foundname, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) +{ + dns_ecdb_t *ecdb = (dns_ecdb_t *)db; + + REQUIRE(VALID_ECDB(ecdb)); + + UNUSED(name); + UNUSED(options); + UNUSED(now); + UNUSED(nodep); + UNUSED(foundname); + UNUSED(rdataset); + UNUSED(sigrdataset); + + return (ISC_R_NOTFOUND); +} + +static isc_result_t +findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, + dns_dbnode_t **nodep) +{ + dns_ecdb_t *ecdb = (dns_ecdb_t *)db; + isc_mem_t *mctx; + dns_ecdbnode_t *node; + isc_result_t result; + + REQUIRE(VALID_ECDB(ecdb)); + REQUIRE(nodep != NULL && *nodep == NULL); + + UNUSED(name); + + if (create != ISC_TRUE) { + /* an 'ephemeral' node is never reused. */ + return (ISC_R_NOTFOUND); + } + + mctx = ecdb->common.mctx; + node = isc_mem_get(mctx, sizeof(*node)); + if (node == NULL) + return (ISC_R_NOMEMORY); + + result = isc_mutex_init(&node->lock); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_mutex_init() failed: %s", + isc_result_totext(result)); + isc_mem_put(mctx, node, sizeof(*node)); + return (ISC_R_UNEXPECTED); + } + + dns_name_init(&node->name, NULL); + result = dns_name_dup(name, mctx, &node->name); + if (result != ISC_R_SUCCESS) { + DESTROYLOCK(&node->lock); + isc_mem_put(mctx, node, sizeof(*node)); + return (result); + } + node->ecdb= ecdb; + node->references = 1; + ISC_LIST_INIT(node->rdatasets); + + ISC_LINK_INIT(node, link); + + LOCK(&ecdb->lock); + ISC_LIST_APPEND(ecdb->nodes, node, link); + UNLOCK(&ecdb->lock); + + node->magic = ECDBNODE_MAGIC; + + *nodep = node; + + return (ISC_R_SUCCESS); +} + +static void +bind_rdataset(dns_ecdb_t *ecdb, dns_ecdbnode_t *node, + rdatasetheader_t *header, dns_rdataset_t *rdataset) +{ + unsigned char *raw; + + /* + * Caller must be holding the node lock. + */ + + REQUIRE(!dns_rdataset_isassociated(rdataset)); + + rdataset->methods = &rdataset_methods; + rdataset->rdclass = ecdb->common.rdclass; + rdataset->type = header->type; + rdataset->covers = header->covers; + rdataset->ttl = header->ttl; + rdataset->trust = header->trust; + if (NXDOMAIN(header)) + rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN; + + rdataset->private1 = ecdb; + rdataset->private2 = node; + raw = (unsigned char *)header + sizeof(*header); + rdataset->private3 = raw; + rdataset->count = 0; + + /* + * Reset iterator state. + */ + rdataset->privateuint4 = 0; + rdataset->private5 = NULL; + + INSIST(node->references > 0); + node->references++; +} + +static isc_result_t +addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options, + dns_rdataset_t *addedrdataset) +{ + dns_ecdb_t *ecdb = (dns_ecdb_t *)db; + isc_region_t r; + isc_result_t result = ISC_R_SUCCESS; + isc_mem_t *mctx; + dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node; + rdatasetheader_t *header; + + REQUIRE(VALID_ECDB(ecdb)); + REQUIRE(VALID_ECDBNODE(ecdbnode)); + + UNUSED(version); + UNUSED(now); + UNUSED(options); + + mctx = ecdb->common.mctx; + + LOCK(&ecdbnode->lock); + + /* + * Sanity check: this implementation does not allow overriding an + * existing rdataset of the same type. + */ + for (header = ISC_LIST_HEAD(ecdbnode->rdatasets); header != NULL; + header = ISC_LIST_NEXT(header, link)) { + INSIST(header->type != rdataset->type || + header->covers != rdataset->covers); + } + + result = dns_rdataslab_fromrdataset(rdataset, mctx, + &r, sizeof(rdatasetheader_t)); + if (result != ISC_R_SUCCESS) + goto unlock; + + header = (rdatasetheader_t *)r.base; + header->type = rdataset->type; + header->ttl = rdataset->ttl; + header->trust = rdataset->trust; + header->covers = rdataset->covers; + header->attributes = 0; + if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) + header->attributes |= RDATASET_ATTR_NXDOMAIN; + ISC_LINK_INIT(header, link); + ISC_LIST_APPEND(ecdbnode->rdatasets, header, link); + + if (addedrdataset == NULL) + goto unlock; + + bind_rdataset(ecdb, ecdbnode, header, addedrdataset); + + unlock: + UNLOCK(&ecdbnode->lock); + + return (result); +} + +static isc_result_t +deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + dns_rdatatype_t type, dns_rdatatype_t covers) +{ + UNUSED(db); + UNUSED(node); + UNUSED(version); + UNUSED(type); + UNUSED(covers); + + return (ISC_R_NOTIMPLEMENTED); +} + +static isc_result_t +createiterator(dns_db_t *db, unsigned int options, + dns_dbiterator_t **iteratorp) +{ + UNUSED(db); + UNUSED(options); + UNUSED(iteratorp); + + return (ISC_R_NOTIMPLEMENTED); +} + +static isc_result_t +allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + isc_stdtime_t now, dns_rdatasetiter_t **iteratorp) +{ + dns_ecdb_t *ecdb = (dns_ecdb_t *)db; + dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node; + isc_mem_t *mctx; + ecdb_rdatasetiter_t *iterator; + + REQUIRE(VALID_ECDB(ecdb)); + REQUIRE(VALID_ECDBNODE(ecdbnode)); + + mctx = ecdb->common.mctx; + + iterator = isc_mem_get(mctx, sizeof(ecdb_rdatasetiter_t)); + if (iterator == NULL) + return (ISC_R_NOMEMORY); + + iterator->common.magic = DNS_RDATASETITER_MAGIC; + iterator->common.methods = &rdatasetiter_methods; + iterator->common.db = db; + iterator->common.node = NULL; + attachnode(db, node, &iterator->common.node); + iterator->common.version = version; + iterator->common.now = now; + + *iteratorp = (dns_rdatasetiter_t *)iterator; + + return (ISC_R_SUCCESS); +} + +static dns_dbmethods_t ecdb_methods = { + attach, + detach, + NULL, /* beginload */ + NULL, /* endload */ + NULL, /* dump */ + NULL, /* currentversion */ + NULL, /* newversion */ + NULL, /* attachversion */ + NULL, /* closeversion */ + findnode, + find, + findzonecut, + attachnode, + detachnode, + NULL, /* expirenode */ + NULL, /* printnode */ + createiterator, /* createiterator */ + NULL, /* findrdataset */ + allrdatasets, + addrdataset, + NULL, /* subtractrdataset */ + deleterdataset, + NULL, /* issecure */ + NULL, /* nodecount */ + NULL, /* ispersistent */ + NULL, /* overmem */ + NULL, /* settask */ + NULL, /* getoriginnode */ + NULL, /* transfernode */ + NULL, /* getnsec3parameters */ + NULL, /* findnsec3node */ + NULL, /* setsigningtime */ + NULL, /* getsigningtime */ + NULL, /* resigned */ + NULL, /* isdnssec */ + NULL, /* getrrsetstats */ + NULL, /* rpz_enabled */ + NULL /* rpz_findips */ +}; + +static isc_result_t +dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type, + dns_rdataclass_t rdclass, unsigned int argc, char *argv[], + void *driverarg, dns_db_t **dbp) +{ + dns_ecdb_t *ecdb; + isc_result_t result; + + REQUIRE(mctx != NULL); + REQUIRE(origin == dns_rootname); + REQUIRE(type == dns_dbtype_cache); + REQUIRE(dbp != NULL && *dbp == NULL); + + UNUSED(argc); + UNUSED(argv); + UNUSED(driverarg); + + ecdb = isc_mem_get(mctx, sizeof(*ecdb)); + if (ecdb == NULL) + return (ISC_R_NOMEMORY); + + ecdb->common.attributes = DNS_DBATTR_CACHE; + ecdb->common.rdclass = rdclass; + ecdb->common.methods = &ecdb_methods; + dns_name_init(&ecdb->common.origin, NULL); + result = dns_name_dupwithoffsets(origin, mctx, &ecdb->common.origin); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, ecdb, sizeof(*ecdb)); + return (result); + } + + result = isc_mutex_init(&ecdb->lock); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_mutex_init() failed: %s", + isc_result_totext(result)); + if (dns_name_dynamic(&ecdb->common.origin)) + dns_name_free(&ecdb->common.origin, mctx); + isc_mem_put(mctx, ecdb, sizeof(*ecdb)); + return (ISC_R_UNEXPECTED); + } + + ecdb->references = 1; + ISC_LIST_INIT(ecdb->nodes); + + ecdb->common.mctx = NULL; + isc_mem_attach(mctx, &ecdb->common.mctx); + ecdb->common.impmagic = ECDB_MAGIC; + ecdb->common.magic = DNS_DB_MAGIC; + + *dbp = (dns_db_t *)ecdb; + + return (ISC_R_SUCCESS); +} + +/*% + * Rdataset Methods + */ + +static void +rdataset_disassociate(dns_rdataset_t *rdataset) { + dns_db_t *db = rdataset->private1; + dns_dbnode_t *node = rdataset->private2; + + dns_db_detachnode(db, &node); +} + +static isc_result_t +rdataset_first(dns_rdataset_t *rdataset) { + unsigned char *raw = rdataset->private3; + unsigned int count; + + count = raw[0] * 256 + raw[1]; + if (count == 0) { + rdataset->private5 = NULL; + return (ISC_R_NOMORE); + } + raw += 2; + /* + * The privateuint4 field is the number of rdata beyond the cursor + * position, so we decrement the total count by one before storing + * it. + */ + count--; + rdataset->privateuint4 = count; + rdataset->private5 = raw; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +rdataset_next(dns_rdataset_t *rdataset) { + unsigned int count; + unsigned int length; + unsigned char *raw; + + count = rdataset->privateuint4; + if (count == 0) + return (ISC_R_NOMORE); + count--; + rdataset->privateuint4 = count; + raw = rdataset->private5; + length = raw[0] * 256 + raw[1]; + raw += length + 2; + rdataset->private5 = raw; + + return (ISC_R_SUCCESS); +} + +static void +rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { + unsigned char *raw = rdataset->private5; + isc_region_t r; + unsigned int length; + unsigned int flags = 0; + + REQUIRE(raw != NULL); + + length = raw[0] * 256 + raw[1]; + raw += 2; + if (rdataset->type == dns_rdatatype_rrsig) { + if (*raw & DNS_RDATASLAB_OFFLINE) + flags |= DNS_RDATA_OFFLINE; + length--; + raw++; + } + r.length = length; + r.base = raw; + dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r); + rdata->flags |= flags; +} + +static void +rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) { + dns_db_t *db = source->private1; + dns_dbnode_t *node = source->private2; + dns_dbnode_t *cloned_node = NULL; + + attachnode(db, node, &cloned_node); + *target = *source; + + /* + * Reset iterator state. + */ + target->privateuint4 = 0; + target->private5 = NULL; +} + +static unsigned int +rdataset_count(dns_rdataset_t *rdataset) { + unsigned char *raw = rdataset->private3; + unsigned int count; + + count = raw[0] * 256 + raw[1]; + + return (count); +} + +static void +rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { + rdatasetheader_t *header = rdataset->private3; + + header--; + header->trust = rdataset->trust = trust; +} + +/* + * Rdataset Iterator Methods + */ + +static void +rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) { + ecdb_rdatasetiter_t *ecdbiterator; + isc_mem_t *mctx; + + REQUIRE(iteratorp != NULL); + ecdbiterator = (ecdb_rdatasetiter_t *)*iteratorp; + REQUIRE(DNS_RDATASETITER_VALID(&ecdbiterator->common)); + + mctx = ecdbiterator->common.db->mctx; + + ecdbiterator->common.magic = 0; + + dns_db_detachnode(ecdbiterator->common.db, &ecdbiterator->common.node); + isc_mem_put(mctx, ecdbiterator, sizeof(ecdb_rdatasetiter_t)); + + *iteratorp = NULL; +} + +static isc_result_t +rdatasetiter_first(dns_rdatasetiter_t *iterator) { + ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator; + dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)iterator->node; + + REQUIRE(DNS_RDATASETITER_VALID(iterator)); + + if (ISC_LIST_EMPTY(ecdbnode->rdatasets)) + return (ISC_R_NOMORE); + ecdbiterator->current = ISC_LIST_HEAD(ecdbnode->rdatasets); + return (ISC_R_SUCCESS); +} + +static isc_result_t +rdatasetiter_next(dns_rdatasetiter_t *iterator) { + ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator; + + REQUIRE(DNS_RDATASETITER_VALID(iterator)); + + ecdbiterator->current = ISC_LIST_NEXT(ecdbiterator->current, link); + if (ecdbiterator->current == NULL) + return (ISC_R_NOMORE); + else + return (ISC_R_SUCCESS); +} + +static void +rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) { + ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator; + dns_ecdb_t *ecdb; + + ecdb = (dns_ecdb_t *)iterator->db; + REQUIRE(VALID_ECDB(ecdb)); + + bind_rdataset(ecdb, iterator->node, ecdbiterator->current, rdataset); +} diff --git a/lib/dns/forward.c b/lib/dns/forward.c index 1406b46..1f9c41a 100644 --- a/lib/dns/forward.c +++ b/lib/dns/forward.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: forward.c,v 1.12 2007-06-19 23:47:16 tbox Exp $ */ +/* $Id: forward.c,v 1.14 2009-09-02 23:48:02 tbox Exp $ */ /*! \file */ @@ -133,11 +133,27 @@ dns_fwdtable_add(dns_fwdtable_t *fwdtable, dns_name_t *name, } isc_result_t +dns_fwdtable_delete(dns_fwdtable_t *fwdtable, dns_name_t *name) { + isc_result_t result; + + REQUIRE(VALID_FWDTABLE(fwdtable)); + + RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write); + result = dns_rbt_deletename(fwdtable->table, name, ISC_FALSE); + RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write); + + if (result == DNS_R_PARTIALMATCH) + result = ISC_R_NOTFOUND; + + return (result); +} + +isc_result_t dns_fwdtable_find(dns_fwdtable_t *fwdtable, dns_name_t *name, dns_forwarders_t **forwardersp) { return (dns_fwdtable_find2(fwdtable, name, NULL, forwardersp)); -} +} isc_result_t dns_fwdtable_find2(dns_fwdtable_t *fwdtable, dns_name_t *name, diff --git a/lib/dns/gen-unix.h b/lib/dns/gen-unix.h index 91cd4d5..47a343d 100644 --- a/lib/dns/gen-unix.h +++ b/lib/dns/gen-unix.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: gen-unix.h,v 1.19.332.2 2009-01-18 23:47:35 tbox Exp $ */ +/* $Id: gen-unix.h,v 1.21 2009-01-17 23:47:42 tbox Exp $ */ /*! \file * \brief diff --git a/lib/dns/gen.c b/lib/dns/gen.c index 6f8ce7d..f1d46ea 100644 --- a/lib/dns/gen.c +++ b/lib/dns/gen.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: gen.c,v 1.83 2008-09-25 04:02:38 tbox Exp $ */ +/* $Id: gen.c,v 1.85 2009-12-04 22:06:37 tbox Exp $ */ /*! \file */ @@ -631,6 +631,8 @@ main(int argc, char **argv) { TOWIRETYPE, TOWIRECLASS, TOWIREDEF); doswitch("COMPARESWITCH", "compare", COMPAREARGS, COMPARETYPE, COMPARECLASS, COMPAREDEF); + doswitch("CASECOMPARESWITCH", "casecompare", COMPAREARGS, + COMPARETYPE, COMPARECLASS, COMPAREDEF); doswitch("FROMSTRUCTSWITCH", "fromstruct", FROMSTRUCTARGS, FROMSTRUCTTYPE, FROMSTRUCTCLASS, FROMSTRUCTDEF); doswitch("TOSTRUCTSWITCH", "tostruct", TOSTRUCTARGS, diff --git a/lib/dns/gssapi_link.c b/lib/dns/gssapi_link.c index a7af67f..e14d0eb 100644 --- a/lib/dns/gssapi_link.c +++ b/lib/dns/gssapi_link.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -16,13 +16,14 @@ */ /* - * $Id: gssapi_link.c,v 1.12 2008-11-11 03:55:01 marka Exp $ + * $Id: gssapi_link.c,v 1.16 2011-01-11 23:47:13 tbox Exp $ */ #include #ifdef GSSAPI +#include #include #include #include @@ -44,6 +45,12 @@ (gb).value = (r).base; \ } while (0) +#define GBUFFER_TO_REGION(gb, r) \ + do { \ + (r).length = (gb).length; \ + (r).base = (gb).value; \ + } while (0) + struct dst_gssapi_signverifyctx { isc_buffer_t *buffer; @@ -254,9 +261,10 @@ gssapi_compare(const dst_key_t *key1, const dst_key_t *key2) { } static isc_result_t -gssapi_generate(dst_key_t *key, int unused) { +gssapi_generate(dst_key_t *key, int unused, void (*callback)(int)) { UNUSED(key); UNUSED(unused); + UNUSED(callback); /* No idea */ return (ISC_R_FAILURE); @@ -275,6 +283,79 @@ gssapi_destroy(dst_key_t *key) { key->keydata.gssctx = NULL; } +static isc_result_t +gssapi_restore(dst_key_t *key, const char *keystr) { + OM_uint32 major, minor; + size_t len; + isc_buffer_t *b = NULL; + isc_region_t r; + gss_buffer_desc gssbuffer; + isc_result_t result; + + len = strlen(keystr); + if ((len % 4) != 0) + return (ISC_R_BADBASE64); + + len = (len / 4) * 3; + + result = isc_buffer_allocate(key->mctx, &b, len); + if (result != ISC_R_SUCCESS) + return (result); + + result = isc_base64_decodestring(keystr, b); + if (result != ISC_R_SUCCESS) { + isc_buffer_free(&b); + return (result); + } + + isc_buffer_remainingregion(b, &r); + REGION_TO_GBUFFER(r, gssbuffer); + major = gss_import_sec_context(&minor, &gssbuffer, + &key->keydata.gssctx); + if (major != GSS_S_COMPLETE) { + isc_buffer_free(&b); + return (ISC_R_FAILURE); + } + + isc_buffer_free(&b); + return (ISC_R_SUCCESS); +} + +static isc_result_t +gssapi_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) { + OM_uint32 major, minor; + gss_buffer_desc gssbuffer; + size_t len; + char *buf; + isc_buffer_t b; + isc_region_t r; + isc_result_t result; + + major = gss_export_sec_context(&minor, &key->keydata.gssctx, + &gssbuffer); + if (major != GSS_S_COMPLETE) { + fprintf(stderr, "gss_export_sec_context -> %d, %d\n", + major, minor); + return (ISC_R_FAILURE); + } + if (gssbuffer.length == 0) + return (ISC_R_FAILURE); + len = ((gssbuffer.length + 2)/3) * 4; + buf = isc_mem_get(mctx, len); + if (buf == NULL) { + gss_release_buffer(&minor, &gssbuffer); + return (ISC_R_NOMEMORY); + } + isc_buffer_init(&b, buf, len); + GBUFFER_TO_REGION(gssbuffer, r); + result = isc_base64_totext(&r, 0, "", &b); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + gss_release_buffer(&minor, &gssbuffer); + *buffer = buf; + *length = len; + return (ISC_R_SUCCESS); +} + static dst_func_t gssapi_functions = { gssapi_create_signverify_ctx, gssapi_destroy_signverify_ctx, @@ -292,7 +373,9 @@ static dst_func_t gssapi_functions = { NULL, /*%< tofile */ NULL, /*%< parse */ NULL, /*%< cleanup */ - NULL /*%< fromlabel */ + NULL, /*%< fromlabel */ + gssapi_dump, + gssapi_restore, }; isc_result_t diff --git a/lib/dns/gssapictx.c b/lib/dns/gssapictx.c index f365a64..707745c 100644 --- a/lib/dns/gssapictx.c +++ b/lib/dns/gssapictx.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,16 +15,18 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: gssapictx.c,v 1.12.118.5 2010-12-22 02:37:55 marka Exp $ */ +/* $Id: gssapictx.c,v 1.26 2011-01-10 03:49:49 marka Exp $ */ #include +#include #include #include #include #include #include +#include #include #include #include @@ -201,9 +203,12 @@ log_cred(const gss_cred_id_t cred) { * - tkey-gssapi-credential doesn't start with DNS/ * - the default realm in /etc/krb5.conf and the * tkey-gssapi-credential bind config option don't match + * + * Note that if tkey-gssapi-keytab is set then these configure checks + * are not performed, and runtime errors from gssapi are used instead */ static void -dst_gssapi_check_config(const char *gss_name) { +check_config(const char *gss_name) { const char *p; krb5_context krb5_ctx; char *krb5_realm = NULL; @@ -263,7 +268,7 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, * here when we're in the acceptor role, which would let us * default the hostname and use a compiled in default service * name of "DNS", giving one less thing to configure in - * named.conf. Unfortunately, this creates a circular + * named.conf. Unfortunately, this creates a circular * dependency due to DNS-based realm lookup in at least one * GSSAPI implementation (Heimdal). Oh well. */ @@ -273,7 +278,7 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname); if (gret != GSS_S_COMPLETE) { - dst_gssapi_check_config((char *)array); + check_config((char *)array); gss_log(3, "failed gss_import_name: %s", gss_error_tostring(gret, minor, buf, @@ -306,7 +311,7 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, initiate ? "initiate" : "accept", (char *)gnamebuf.value, gss_error_tostring(gret, minor, buf, sizeof(buf))); - dst_gssapi_check_config((char *)array); + check_config((char *)array); return (ISC_R_FAILURE); } @@ -361,7 +366,7 @@ dst_gssapi_identitymatchesrealmkrb5(dns_name_t *signer, dns_name_t *name, rname++; /* - * Find the host portion of the signer's name. We do this by + * Find the host portion of the signer's name. We do this by * searching for the first / character. We then check to make * certain the instance name is "host" * @@ -440,7 +445,7 @@ dst_gssapi_identitymatchesrealmms(dns_name_t *signer, dns_name_t *name, return (isc_boolean_false); /* - * Find the host portion of the signer's name. Zero out the $ so + * Find the host portion of the signer's name. Zero out the $ so * it terminates the signer's name, and skip past the @ for * the realm. * @@ -454,7 +459,7 @@ dst_gssapi_identitymatchesrealmms(dns_name_t *signer, dns_name_t *name, /* * Find the first . in the target name, and make it the end of - * the string. The rest of the name has to match the realm. + * the string. The rest of the name has to match the realm. */ if (name != NULL) { nname = strchr(nbuf, '.'); @@ -510,9 +515,34 @@ dst_gssapi_releasecred(gss_cred_id_t *cred) { #endif } +#ifdef GSSAPI +/* + * Format a gssapi error message info into a char ** on the given memory + * context. This is used to return gssapi error messages back up the + * call chain for reporting to the user. + */ +static void +gss_err_message(isc_mem_t *mctx, isc_uint32_t major, isc_uint32_t minor, + char **err_message) +{ + char buf[1024]; + char *estr; + + if (err_message == NULL || mctx == NULL) { + /* the caller doesn't want any error messages */ + return; + } + + estr = gss_error_tostring(major, minor, buf, sizeof(buf)); + if (estr) + (*err_message) = isc_mem_strdup(mctx, estr); +} +#endif + isc_result_t dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, - isc_buffer_t *outtoken, gss_ctx_id_t *gssctx) + isc_buffer_t *outtoken, gss_ctx_id_t *gssctx, + isc_mem_t *mctx, char **err_message) { #ifdef GSSAPI isc_region_t r; @@ -523,10 +553,10 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, isc_result_t result; gss_buffer_desc gnamebuf; unsigned char array[DNS_NAME_MAXTEXT + 1]; - char buf[1024]; /* Client must pass us a valid gss_ctx_id_t here */ REQUIRE(gssctx != NULL); + REQUIRE(mctx != NULL); isc_buffer_init(&namebuf, array, sizeof(array)); name_to_gbuffer(name, &namebuf, &gnamebuf); @@ -534,6 +564,7 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, /* Get the name as a GSS name */ gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname); if (gret != GSS_S_COMPLETE) { + gss_err_message(mctx, gret, minor, err_message); result = ISC_R_FAILURE; goto out; } @@ -550,8 +581,7 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, * Note that we don't set GSS_C_SEQUENCE_FLAG as Windows DNS * servers don't like it. */ - flags = GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG | - GSS_C_INTEG_FLAG; + flags = GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG; gret = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, gssctx, gname, GSS_SPNEGO_MECHANISM, flags, @@ -559,9 +589,9 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, NULL, &gouttoken, &ret_flags, NULL); if (gret != GSS_S_COMPLETE && gret != GSS_S_CONTINUE_NEEDED) { - gss_log(3, "Failure initiating security context"); - gss_log(3, "%s", gss_error_tostring(gret, minor, - buf, sizeof(buf))); + gss_err_message(mctx, gret, minor, err_message); + gss_log(3, "Failure initiating security context: %s", + *err_message); result = ISC_R_FAILURE; goto out; } @@ -593,6 +623,8 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, UNUSED(intoken); UNUSED(outtoken); UNUSED(gssctx); + UNUSED(mctx); + UNUSED(err_message); return (ISC_R_NOTIMPLEMENTED); #endif @@ -600,6 +632,7 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, isc_result_t dst_gssapi_acceptctx(gss_cred_id_t cred, + const char *gssapi_keytab, isc_region_t *intoken, isc_buffer_t **outtoken, gss_ctx_id_t *ctxout, dns_name_t *principal, isc_mem_t *mctx) @@ -626,6 +659,34 @@ dst_gssapi_acceptctx(gss_cred_id_t cred, else context = *ctxout; + if (gssapi_keytab != NULL) { +#ifdef ISC_PLATFORM_GSSAPI_KRB5_HEADER + gret = gsskrb5_register_acceptor_identity(gssapi_keytab); + if (gret != GSS_S_COMPLETE) { + gss_log(3, "failed " + "gsskrb5_register_acceptor_identity(%s): %s", + gssapi_keytab, + gss_error_tostring(gret, minor, + buf, sizeof(buf))); + return (DNS_R_INVALIDTKEY); + } +#else + /* + * Minimize memory leakage by only setting KRB5_KTNAME + * if it needs to change. + */ + const char *old = getenv("KRB5_KTNAME"); + if (old == NULL || strcmp(old, gssapi_keytab) != 0) { + char *kt = malloc(strlen(gssapi_keytab) + 13); + if (kt == NULL) + return (ISC_R_NOMEMORY); + sprintf(kt, "KRB5_KTNAME=%s", gssapi_keytab); + if (putenv(kt) != 0) + return (ISC_R_NOMEMORY); + } +#endif + } + gret = gss_accept_sec_context(&minor, &context, cred, &gintoken, GSS_C_NO_CHANNEL_BINDINGS, &gname, NULL, &gouttoken, NULL, NULL, NULL); @@ -692,7 +753,7 @@ dst_gssapi_acceptctx(gss_cred_id_t cred, isc_buffer_add(&namebuf, r.length); RETERR(dns_name_fromtext(principal, &namebuf, dns_rootname, - ISC_FALSE, NULL)); + 0, NULL)); if (gnamebuf.length != 0) { gret = gss_release_buffer(&minor, &gnamebuf); @@ -717,6 +778,7 @@ dst_gssapi_acceptctx(gss_cred_id_t cred, return (result); #else UNUSED(cred); + UNUSED(gssapi_keytab); UNUSED(intoken); UNUSED(outtoken); UNUSED(ctxout); diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c index 5d6dce7..ecc4089 100644 --- a/lib/dns/hmac_link.c +++ b/lib/dns/hmac_link.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -31,7 +31,7 @@ /* * Principal Author: Brian Wellington - * $Id: hmac_link.c,v 1.11 2008-04-01 23:47:10 tbox Exp $ + * $Id: hmac_link.c,v 1.19 2011-01-11 23:47:13 tbox Exp $ */ #include @@ -50,14 +50,10 @@ #include "dst_internal.h" #include "dst_parse.h" -#define HMAC_LEN 64 -#define HMAC_IPAD 0x36 -#define HMAC_OPAD 0x5c - static isc_result_t hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data); struct dst_hmacmd5_key { - unsigned char key[HMAC_LEN]; + unsigned char key[ISC_MD5_BLOCK_LENGTH]; }; static isc_result_t @@ -79,7 +75,7 @@ hmacmd5_createctx(dst_key_t *key, dst_context_t *dctx) { hmacmd5ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacmd5_t)); if (hmacmd5ctx == NULL) return (ISC_R_NOMEMORY); - isc_hmacmd5_init(hmacmd5ctx, hkey->key, HMAC_LEN); + isc_hmacmd5_init(hmacmd5ctx, hkey->key, ISC_SHA1_BLOCK_LENGTH); dctx->ctxdata.hmacmd5ctx = hmacmd5ctx; return (ISC_R_SUCCESS); } @@ -142,26 +138,28 @@ hmacmd5_compare(const dst_key_t *key1, const dst_key_t *key2) { else if (hkey1 == NULL || hkey2 == NULL) return (ISC_FALSE); - if (memcmp(hkey1->key, hkey2->key, HMAC_LEN) == 0) + if (memcmp(hkey1->key, hkey2->key, ISC_SHA1_BLOCK_LENGTH) == 0) return (ISC_TRUE); else return (ISC_FALSE); } static isc_result_t -hmacmd5_generate(dst_key_t *key, int pseudorandom_ok) { +hmacmd5_generate(dst_key_t *key, int pseudorandom_ok, void (*callback)(int)) { isc_buffer_t b; isc_result_t ret; - int bytes; - unsigned char data[HMAC_LEN]; + unsigned int bytes; + unsigned char data[ISC_SHA1_BLOCK_LENGTH]; + + UNUSED(callback); bytes = (key->key_size + 7) / 8; - if (bytes > HMAC_LEN) { - bytes = HMAC_LEN; - key->key_size = HMAC_LEN * 8; + if (bytes > ISC_SHA1_BLOCK_LENGTH) { + bytes = ISC_SHA1_BLOCK_LENGTH; + key->key_size = ISC_SHA1_BLOCK_LENGTH * 8; } - memset(data, 0, HMAC_LEN); + memset(data, 0, ISC_SHA1_BLOCK_LENGTH); ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0)); if (ret != ISC_R_SUCCESS) @@ -170,7 +168,7 @@ hmacmd5_generate(dst_key_t *key, int pseudorandom_ok) { isc_buffer_init(&b, data, bytes); isc_buffer_add(&b, bytes); ret = hmacmd5_fromdns(key, &b); - memset(data, 0, HMAC_LEN); + memset(data, 0, ISC_SHA1_BLOCK_LENGTH); return (ret); } @@ -184,6 +182,7 @@ hmacmd5_isprivate(const dst_key_t *key) { static void hmacmd5_destroy(dst_key_t *key) { dst_hmacmd5_key_t *hkey = key->keydata.hmacmd5; + memset(hkey, 0, sizeof(dst_hmacmd5_key_t)); isc_mem_put(key->mctx, hkey, sizeof(dst_hmacmd5_key_t)); key->keydata.hmacmd5 = NULL; @@ -223,7 +222,7 @@ hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) { memset(hkey->key, 0, sizeof(hkey->key)); - if (r.length > HMAC_LEN) { + if (r.length > ISC_SHA1_BLOCK_LENGTH) { isc_md5_init(&md5ctx); isc_md5_update(&md5ctx, r.base, r.length); isc_md5_final(&md5ctx, hkey->key); @@ -268,15 +267,17 @@ hmacmd5_tofile(const dst_key_t *key, const char *directory) { } static isc_result_t -hmacmd5_parse(dst_key_t *key, isc_lex_t *lexer) { +hmacmd5_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t result, tresult; isc_buffer_t b; isc_mem_t *mctx = key->mctx; unsigned int i; + UNUSED(pub); /* read private key file */ - result = dst__privstruct_parse(key, DST_ALG_HMACMD5, lexer, mctx, &priv); + result = dst__privstruct_parse(key, DST_ALG_HMACMD5, lexer, mctx, + &priv); if (result != ISC_R_SUCCESS) return (result); @@ -324,6 +325,8 @@ static dst_func_t hmacmd5_functions = { hmacmd5_parse, NULL, /*%< cleanup */ NULL, /*%< fromlabel */ + NULL, /*%< dump */ + NULL, /*%< restore */ }; isc_result_t @@ -337,7 +340,7 @@ dst__hmacmd5_init(dst_func_t **funcp) { static isc_result_t hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data); struct dst_hmacsha1_key { - unsigned char key[ISC_SHA1_DIGESTLENGTH]; + unsigned char key[ISC_SHA1_BLOCK_LENGTH]; }; static isc_result_t @@ -348,7 +351,7 @@ hmacsha1_createctx(dst_key_t *key, dst_context_t *dctx) { hmacsha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha1_t)); if (hmacsha1ctx == NULL) return (ISC_R_NOMEMORY); - isc_hmacsha1_init(hmacsha1ctx, hkey->key, ISC_SHA1_DIGESTLENGTH); + isc_hmacsha1_init(hmacsha1ctx, hkey->key, ISC_SHA1_BLOCK_LENGTH); dctx->ctxdata.hmacsha1ctx = hmacsha1ctx; return (ISC_R_SUCCESS); } @@ -411,26 +414,28 @@ hmacsha1_compare(const dst_key_t *key1, const dst_key_t *key2) { else if (hkey1 == NULL || hkey2 == NULL) return (ISC_FALSE); - if (memcmp(hkey1->key, hkey2->key, ISC_SHA1_DIGESTLENGTH) == 0) + if (memcmp(hkey1->key, hkey2->key, ISC_SHA1_BLOCK_LENGTH) == 0) return (ISC_TRUE); else return (ISC_FALSE); } static isc_result_t -hmacsha1_generate(dst_key_t *key, int pseudorandom_ok) { +hmacsha1_generate(dst_key_t *key, int pseudorandom_ok, void (*callback)(int)) { isc_buffer_t b; isc_result_t ret; - int bytes; - unsigned char data[HMAC_LEN]; + unsigned int bytes; + unsigned char data[ISC_SHA1_BLOCK_LENGTH]; + + UNUSED(callback); bytes = (key->key_size + 7) / 8; - if (bytes > HMAC_LEN) { - bytes = HMAC_LEN; - key->key_size = HMAC_LEN * 8; + if (bytes > ISC_SHA1_BLOCK_LENGTH) { + bytes = ISC_SHA1_BLOCK_LENGTH; + key->key_size = ISC_SHA1_BLOCK_LENGTH * 8; } - memset(data, 0, HMAC_LEN); + memset(data, 0, ISC_SHA1_BLOCK_LENGTH); ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0)); if (ret != ISC_R_SUCCESS) @@ -439,7 +444,7 @@ hmacsha1_generate(dst_key_t *key, int pseudorandom_ok) { isc_buffer_init(&b, data, bytes); isc_buffer_add(&b, bytes); ret = hmacsha1_fromdns(key, &b); - memset(data, 0, ISC_SHA1_DIGESTLENGTH); + memset(data, 0, ISC_SHA1_BLOCK_LENGTH); return (ret); } @@ -453,6 +458,7 @@ hmacsha1_isprivate(const dst_key_t *key) { static void hmacsha1_destroy(dst_key_t *key) { dst_hmacsha1_key_t *hkey = key->keydata.hmacsha1; + memset(hkey, 0, sizeof(dst_hmacsha1_key_t)); isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha1_key_t)); key->keydata.hmacsha1 = NULL; @@ -492,7 +498,7 @@ hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) { memset(hkey->key, 0, sizeof(hkey->key)); - if (r.length > ISC_SHA1_DIGESTLENGTH) { + if (r.length > ISC_SHA1_BLOCK_LENGTH) { isc_sha1_init(&sha1ctx); isc_sha1_update(&sha1ctx, r.base, r.length); isc_sha1_final(&sha1ctx, hkey->key); @@ -537,13 +543,14 @@ hmacsha1_tofile(const dst_key_t *key, const char *directory) { } static isc_result_t -hmacsha1_parse(dst_key_t *key, isc_lex_t *lexer) { +hmacsha1_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t result, tresult; isc_buffer_t b; isc_mem_t *mctx = key->mctx; unsigned int i; + UNUSED(pub); /* read private key file */ result = dst__privstruct_parse(key, DST_ALG_HMACSHA1, lexer, mctx, &priv); @@ -594,6 +601,8 @@ static dst_func_t hmacsha1_functions = { hmacsha1_parse, NULL, /* cleanup */ NULL, /* fromlabel */ + NULL, /* dump */ + NULL, /* restore */ }; isc_result_t @@ -607,7 +616,7 @@ dst__hmacsha1_init(dst_func_t **funcp) { static isc_result_t hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data); struct dst_hmacsha224_key { - unsigned char key[ISC_SHA224_DIGESTLENGTH]; + unsigned char key[ISC_SHA224_BLOCK_LENGTH]; }; static isc_result_t @@ -618,7 +627,7 @@ hmacsha224_createctx(dst_key_t *key, dst_context_t *dctx) { hmacsha224ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha224_t)); if (hmacsha224ctx == NULL) return (ISC_R_NOMEMORY); - isc_hmacsha224_init(hmacsha224ctx, hkey->key, ISC_SHA224_DIGESTLENGTH); + isc_hmacsha224_init(hmacsha224ctx, hkey->key, ISC_SHA224_BLOCK_LENGTH); dctx->ctxdata.hmacsha224ctx = hmacsha224ctx; return (ISC_R_SUCCESS); } @@ -681,26 +690,30 @@ hmacsha224_compare(const dst_key_t *key1, const dst_key_t *key2) { else if (hkey1 == NULL || hkey2 == NULL) return (ISC_FALSE); - if (memcmp(hkey1->key, hkey2->key, ISC_SHA224_DIGESTLENGTH) == 0) + if (memcmp(hkey1->key, hkey2->key, ISC_SHA224_BLOCK_LENGTH) == 0) return (ISC_TRUE); else return (ISC_FALSE); } static isc_result_t -hmacsha224_generate(dst_key_t *key, int pseudorandom_ok) { +hmacsha224_generate(dst_key_t *key, int pseudorandom_ok, + void (*callback)(int)) +{ isc_buffer_t b; isc_result_t ret; - int bytes; - unsigned char data[HMAC_LEN]; + unsigned int bytes; + unsigned char data[ISC_SHA224_BLOCK_LENGTH]; + + UNUSED(callback); bytes = (key->key_size + 7) / 8; - if (bytes > HMAC_LEN) { - bytes = HMAC_LEN; - key->key_size = HMAC_LEN * 8; + if (bytes > ISC_SHA224_BLOCK_LENGTH) { + bytes = ISC_SHA224_BLOCK_LENGTH; + key->key_size = ISC_SHA224_BLOCK_LENGTH * 8; } - memset(data, 0, HMAC_LEN); + memset(data, 0, ISC_SHA224_BLOCK_LENGTH); ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0)); if (ret != ISC_R_SUCCESS) @@ -709,7 +722,7 @@ hmacsha224_generate(dst_key_t *key, int pseudorandom_ok) { isc_buffer_init(&b, data, bytes); isc_buffer_add(&b, bytes); ret = hmacsha224_fromdns(key, &b); - memset(data, 0, ISC_SHA224_DIGESTLENGTH); + memset(data, 0, ISC_SHA224_BLOCK_LENGTH); return (ret); } @@ -723,6 +736,7 @@ hmacsha224_isprivate(const dst_key_t *key) { static void hmacsha224_destroy(dst_key_t *key) { dst_hmacsha224_key_t *hkey = key->keydata.hmacsha224; + memset(hkey, 0, sizeof(dst_hmacsha224_key_t)); isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha224_key_t)); key->keydata.hmacsha224 = NULL; @@ -762,7 +776,7 @@ hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) { memset(hkey->key, 0, sizeof(hkey->key)); - if (r.length > ISC_SHA224_DIGESTLENGTH) { + if (r.length > ISC_SHA224_BLOCK_LENGTH) { isc_sha224_init(&sha224ctx); isc_sha224_update(&sha224ctx, r.base, r.length); isc_sha224_final(hkey->key, &sha224ctx); @@ -807,13 +821,14 @@ hmacsha224_tofile(const dst_key_t *key, const char *directory) { } static isc_result_t -hmacsha224_parse(dst_key_t *key, isc_lex_t *lexer) { +hmacsha224_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t result, tresult; isc_buffer_t b; isc_mem_t *mctx = key->mctx; unsigned int i; + UNUSED(pub); /* read private key file */ result = dst__privstruct_parse(key, DST_ALG_HMACSHA224, lexer, mctx, &priv); @@ -864,6 +879,8 @@ static dst_func_t hmacsha224_functions = { hmacsha224_parse, NULL, /* cleanup */ NULL, /* fromlabel */ + NULL, /* dump */ + NULL, /* restore */ }; isc_result_t @@ -877,7 +894,7 @@ dst__hmacsha224_init(dst_func_t **funcp) { static isc_result_t hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data); struct dst_hmacsha256_key { - unsigned char key[ISC_SHA256_DIGESTLENGTH]; + unsigned char key[ISC_SHA256_BLOCK_LENGTH]; }; static isc_result_t @@ -888,7 +905,7 @@ hmacsha256_createctx(dst_key_t *key, dst_context_t *dctx) { hmacsha256ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha256_t)); if (hmacsha256ctx == NULL) return (ISC_R_NOMEMORY); - isc_hmacsha256_init(hmacsha256ctx, hkey->key, ISC_SHA256_DIGESTLENGTH); + isc_hmacsha256_init(hmacsha256ctx, hkey->key, ISC_SHA256_BLOCK_LENGTH); dctx->ctxdata.hmacsha256ctx = hmacsha256ctx; return (ISC_R_SUCCESS); } @@ -951,26 +968,30 @@ hmacsha256_compare(const dst_key_t *key1, const dst_key_t *key2) { else if (hkey1 == NULL || hkey2 == NULL) return (ISC_FALSE); - if (memcmp(hkey1->key, hkey2->key, ISC_SHA256_DIGESTLENGTH) == 0) + if (memcmp(hkey1->key, hkey2->key, ISC_SHA256_BLOCK_LENGTH) == 0) return (ISC_TRUE); else return (ISC_FALSE); } static isc_result_t -hmacsha256_generate(dst_key_t *key, int pseudorandom_ok) { +hmacsha256_generate(dst_key_t *key, int pseudorandom_ok, + void (*callback)(int)) +{ isc_buffer_t b; isc_result_t ret; - int bytes; - unsigned char data[HMAC_LEN]; + unsigned int bytes; + unsigned char data[ISC_SHA256_BLOCK_LENGTH]; + + UNUSED(callback); bytes = (key->key_size + 7) / 8; - if (bytes > HMAC_LEN) { - bytes = HMAC_LEN; - key->key_size = HMAC_LEN * 8; + if (bytes > ISC_SHA256_BLOCK_LENGTH) { + bytes = ISC_SHA256_BLOCK_LENGTH; + key->key_size = ISC_SHA256_BLOCK_LENGTH * 8; } - memset(data, 0, HMAC_LEN); + memset(data, 0, ISC_SHA256_BLOCK_LENGTH); ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0)); if (ret != ISC_R_SUCCESS) @@ -979,7 +1000,7 @@ hmacsha256_generate(dst_key_t *key, int pseudorandom_ok) { isc_buffer_init(&b, data, bytes); isc_buffer_add(&b, bytes); ret = hmacsha256_fromdns(key, &b); - memset(data, 0, ISC_SHA256_DIGESTLENGTH); + memset(data, 0, ISC_SHA256_BLOCK_LENGTH); return (ret); } @@ -993,6 +1014,7 @@ hmacsha256_isprivate(const dst_key_t *key) { static void hmacsha256_destroy(dst_key_t *key) { dst_hmacsha256_key_t *hkey = key->keydata.hmacsha256; + memset(hkey, 0, sizeof(dst_hmacsha256_key_t)); isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha256_key_t)); key->keydata.hmacsha256 = NULL; @@ -1032,7 +1054,7 @@ hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) { memset(hkey->key, 0, sizeof(hkey->key)); - if (r.length > ISC_SHA256_DIGESTLENGTH) { + if (r.length > ISC_SHA256_BLOCK_LENGTH) { isc_sha256_init(&sha256ctx); isc_sha256_update(&sha256ctx, r.base, r.length); isc_sha256_final(hkey->key, &sha256ctx); @@ -1077,13 +1099,14 @@ hmacsha256_tofile(const dst_key_t *key, const char *directory) { } static isc_result_t -hmacsha256_parse(dst_key_t *key, isc_lex_t *lexer) { +hmacsha256_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t result, tresult; isc_buffer_t b; isc_mem_t *mctx = key->mctx; unsigned int i; + UNUSED(pub); /* read private key file */ result = dst__privstruct_parse(key, DST_ALG_HMACSHA256, lexer, mctx, &priv); @@ -1134,6 +1157,8 @@ static dst_func_t hmacsha256_functions = { hmacsha256_parse, NULL, /* cleanup */ NULL, /* fromlabel */ + NULL, /* dump */ + NULL, /* restore */ }; isc_result_t @@ -1147,7 +1172,7 @@ dst__hmacsha256_init(dst_func_t **funcp) { static isc_result_t hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data); struct dst_hmacsha384_key { - unsigned char key[ISC_SHA384_DIGESTLENGTH]; + unsigned char key[ISC_SHA384_BLOCK_LENGTH]; }; static isc_result_t @@ -1158,7 +1183,7 @@ hmacsha384_createctx(dst_key_t *key, dst_context_t *dctx) { hmacsha384ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha384_t)); if (hmacsha384ctx == NULL) return (ISC_R_NOMEMORY); - isc_hmacsha384_init(hmacsha384ctx, hkey->key, ISC_SHA384_DIGESTLENGTH); + isc_hmacsha384_init(hmacsha384ctx, hkey->key, ISC_SHA384_BLOCK_LENGTH); dctx->ctxdata.hmacsha384ctx = hmacsha384ctx; return (ISC_R_SUCCESS); } @@ -1221,26 +1246,30 @@ hmacsha384_compare(const dst_key_t *key1, const dst_key_t *key2) { else if (hkey1 == NULL || hkey2 == NULL) return (ISC_FALSE); - if (memcmp(hkey1->key, hkey2->key, ISC_SHA384_DIGESTLENGTH) == 0) + if (memcmp(hkey1->key, hkey2->key, ISC_SHA384_BLOCK_LENGTH) == 0) return (ISC_TRUE); else return (ISC_FALSE); } static isc_result_t -hmacsha384_generate(dst_key_t *key, int pseudorandom_ok) { +hmacsha384_generate(dst_key_t *key, int pseudorandom_ok, + void (*callback)(int)) +{ isc_buffer_t b; isc_result_t ret; - int bytes; - unsigned char data[HMAC_LEN]; + unsigned int bytes; + unsigned char data[ISC_SHA384_BLOCK_LENGTH]; + + UNUSED(callback); bytes = (key->key_size + 7) / 8; - if (bytes > HMAC_LEN) { - bytes = HMAC_LEN; - key->key_size = HMAC_LEN * 8; + if (bytes > ISC_SHA384_BLOCK_LENGTH) { + bytes = ISC_SHA384_BLOCK_LENGTH; + key->key_size = ISC_SHA384_BLOCK_LENGTH * 8; } - memset(data, 0, HMAC_LEN); + memset(data, 0, ISC_SHA384_BLOCK_LENGTH); ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0)); if (ret != ISC_R_SUCCESS) @@ -1249,7 +1278,7 @@ hmacsha384_generate(dst_key_t *key, int pseudorandom_ok) { isc_buffer_init(&b, data, bytes); isc_buffer_add(&b, bytes); ret = hmacsha384_fromdns(key, &b); - memset(data, 0, ISC_SHA384_DIGESTLENGTH); + memset(data, 0, ISC_SHA384_BLOCK_LENGTH); return (ret); } @@ -1263,6 +1292,7 @@ hmacsha384_isprivate(const dst_key_t *key) { static void hmacsha384_destroy(dst_key_t *key) { dst_hmacsha384_key_t *hkey = key->keydata.hmacsha384; + memset(hkey, 0, sizeof(dst_hmacsha384_key_t)); isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha384_key_t)); key->keydata.hmacsha384 = NULL; @@ -1302,7 +1332,7 @@ hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) { memset(hkey->key, 0, sizeof(hkey->key)); - if (r.length > ISC_SHA384_DIGESTLENGTH) { + if (r.length > ISC_SHA384_BLOCK_LENGTH) { isc_sha384_init(&sha384ctx); isc_sha384_update(&sha384ctx, r.base, r.length); isc_sha384_final(hkey->key, &sha384ctx); @@ -1347,13 +1377,14 @@ hmacsha384_tofile(const dst_key_t *key, const char *directory) { } static isc_result_t -hmacsha384_parse(dst_key_t *key, isc_lex_t *lexer) { +hmacsha384_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t result, tresult; isc_buffer_t b; isc_mem_t *mctx = key->mctx; unsigned int i; + UNUSED(pub); /* read private key file */ result = dst__privstruct_parse(key, DST_ALG_HMACSHA384, lexer, mctx, &priv); @@ -1404,6 +1435,8 @@ static dst_func_t hmacsha384_functions = { hmacsha384_parse, NULL, /* cleanup */ NULL, /* fromlabel */ + NULL, /* dump */ + NULL, /* restore */ }; isc_result_t @@ -1417,7 +1450,7 @@ dst__hmacsha384_init(dst_func_t **funcp) { static isc_result_t hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data); struct dst_hmacsha512_key { - unsigned char key[ISC_SHA512_DIGESTLENGTH]; + unsigned char key[ISC_SHA512_BLOCK_LENGTH]; }; static isc_result_t @@ -1428,7 +1461,7 @@ hmacsha512_createctx(dst_key_t *key, dst_context_t *dctx) { hmacsha512ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha512_t)); if (hmacsha512ctx == NULL) return (ISC_R_NOMEMORY); - isc_hmacsha512_init(hmacsha512ctx, hkey->key, ISC_SHA512_DIGESTLENGTH); + isc_hmacsha512_init(hmacsha512ctx, hkey->key, ISC_SHA512_BLOCK_LENGTH); dctx->ctxdata.hmacsha512ctx = hmacsha512ctx; return (ISC_R_SUCCESS); } @@ -1491,26 +1524,30 @@ hmacsha512_compare(const dst_key_t *key1, const dst_key_t *key2) { else if (hkey1 == NULL || hkey2 == NULL) return (ISC_FALSE); - if (memcmp(hkey1->key, hkey2->key, ISC_SHA512_DIGESTLENGTH) == 0) + if (memcmp(hkey1->key, hkey2->key, ISC_SHA512_BLOCK_LENGTH) == 0) return (ISC_TRUE); else return (ISC_FALSE); } static isc_result_t -hmacsha512_generate(dst_key_t *key, int pseudorandom_ok) { +hmacsha512_generate(dst_key_t *key, int pseudorandom_ok, + void (*callback)(int)) +{ isc_buffer_t b; isc_result_t ret; - int bytes; - unsigned char data[HMAC_LEN]; + unsigned int bytes; + unsigned char data[ISC_SHA512_BLOCK_LENGTH]; + + UNUSED(callback); bytes = (key->key_size + 7) / 8; - if (bytes > HMAC_LEN) { - bytes = HMAC_LEN; - key->key_size = HMAC_LEN * 8; + if (bytes > ISC_SHA512_BLOCK_LENGTH) { + bytes = ISC_SHA512_BLOCK_LENGTH; + key->key_size = ISC_SHA512_BLOCK_LENGTH * 8; } - memset(data, 0, HMAC_LEN); + memset(data, 0, ISC_SHA512_BLOCK_LENGTH); ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0)); if (ret != ISC_R_SUCCESS) @@ -1519,7 +1556,7 @@ hmacsha512_generate(dst_key_t *key, int pseudorandom_ok) { isc_buffer_init(&b, data, bytes); isc_buffer_add(&b, bytes); ret = hmacsha512_fromdns(key, &b); - memset(data, 0, ISC_SHA512_DIGESTLENGTH); + memset(data, 0, ISC_SHA512_BLOCK_LENGTH); return (ret); } @@ -1533,6 +1570,7 @@ hmacsha512_isprivate(const dst_key_t *key) { static void hmacsha512_destroy(dst_key_t *key) { dst_hmacsha512_key_t *hkey = key->keydata.hmacsha512; + memset(hkey, 0, sizeof(dst_hmacsha512_key_t)); isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha512_key_t)); key->keydata.hmacsha512 = NULL; @@ -1572,7 +1610,7 @@ hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) { memset(hkey->key, 0, sizeof(hkey->key)); - if (r.length > ISC_SHA512_DIGESTLENGTH) { + if (r.length > ISC_SHA512_BLOCK_LENGTH) { isc_sha512_init(&sha512ctx); isc_sha512_update(&sha512ctx, r.base, r.length); isc_sha512_final(hkey->key, &sha512ctx); @@ -1617,13 +1655,14 @@ hmacsha512_tofile(const dst_key_t *key, const char *directory) { } static isc_result_t -hmacsha512_parse(dst_key_t *key, isc_lex_t *lexer) { +hmacsha512_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t result, tresult; isc_buffer_t b; isc_mem_t *mctx = key->mctx; unsigned int i; + UNUSED(pub); /* read private key file */ result = dst__privstruct_parse(key, DST_ALG_HMACSHA512, lexer, mctx, &priv); @@ -1674,6 +1713,8 @@ static dst_func_t hmacsha512_functions = { hmacsha512_parse, NULL, /* cleanup */ NULL, /* fromlabel */ + NULL, /* dump */ + NULL, /* restore */ }; isc_result_t diff --git a/lib/dns/include/dns/Makefile.in b/lib/dns/include/dns/Makefile.in index a4cd810..e13d084 100644 --- a/lib/dns/include/dns/Makefile.in +++ b/lib/dns/include/dns/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2004, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 1998-2003 Internet Software Consortium. # # Permission to use, copy, modify, and/or distribute this software for any @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.55 2008-11-14 23:47:33 tbox Exp $ +# $Id: Makefile.in,v 1.57 2009-10-08 23:48:10 tbox Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -21,19 +21,17 @@ top_srcdir = @top_srcdir@ @BIND9_VERSION@ -HEADERS = acl.h adb.h byaddr.h cache.h callbacks.h \ - cert.h compress.h \ +HEADERS = acl.h adb.h byaddr.h cache.h callbacks.h cert.h compress.h \ db.h dbiterator.h dbtable.h diff.h dispatch.h dlz.h \ - dnssec.h ds.h events.h fixedname.h iptable.h journal.h keyflags.h \ - keytable.h keyvalues.h lib.h log.h master.h masterdump.h \ - message.h name.h ncache.h \ - nsec.h peer.h portlist.h rbt.h rcode.h \ + dnssec.h ds.h events.h fixedname.h iptable.h journal.h \ + keyflags.h keytable.h keyvalues.h lib.h log.h \ + master.h masterdump.h message.h name.h ncache.h nsec.h \ + peer.h portlist.h private.h rbt.h rcode.h \ rdata.h rdataclass.h rdatalist.h rdataset.h rdatasetiter.h \ rdataslab.h rdatatype.h request.h resolver.h result.h \ rootns.h sdb.h sdlz.h secalg.h secproto.h soa.h ssu.h \ - tcpmsg.h time.h tkey.h \ - tsig.h ttl.h types.h validator.h version.h view.h xfrin.h \ - zone.h zonekey.h zt.h + tcpmsg.h time.h tkey.h tsig.h ttl.h types.h \ + validator.h version.h view.h xfrin.h zone.h zonekey.h zt.h GENHEADERS = enumclass.h enumtype.h rdatastruct.h diff --git a/lib/dns/include/dns/acl.h b/lib/dns/include/dns/acl.h index 1045cd2..04f5577 100644 --- a/lib/dns/include/dns/acl.h +++ b/lib/dns/include/dns/acl.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: acl.h,v 1.31.206.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: acl.h,v 1.33 2009-01-17 23:47:43 tbox Exp $ */ #ifndef DNS_ACL_H #define DNS_ACL_H 1 diff --git a/lib/dns/include/dns/cache.h b/lib/dns/include/dns/cache.h index 94077d6..e4ea5f4 100644 --- a/lib/dns/include/dns/cache.h +++ b/lib/dns/include/dns/cache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cache.h,v 1.26 2007-06-19 23:47:16 tbox Exp $ */ +/* $Id: cache.h,v 1.28 2009-01-09 23:47:46 tbox Exp $ */ #ifndef DNS_CACHE_H #define DNS_CACHE_H 1 @@ -65,8 +65,15 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr, dns_rdataclass_t rdclass, const char *db_type, unsigned int db_argc, char **db_argv, dns_cache_t **cachep); +isc_result_t +dns_cache_create2(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + isc_timermgr_t *timermgr, dns_rdataclass_t rdclass, + const char *cachename, const char *db_type, + unsigned int db_argc, char **db_argv, dns_cache_t **cachep); /*%< - * Create a new DNS cache. + * Create a new DNS cache. dns_cache_create2() will create a named cache. + * dns_cache_create() is a backward compatible version that internally specifies + * an empty name. * * Requires: * @@ -76,6 +83,8 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, * manager, or both are NULL. If NULL, no periodic cleaning of the * cache will take place. * + *\li 'cachename' is a valid string. This must not be NULL. + * *\li 'cachep' is a valid pointer, and *cachep == NULL * * Ensures: @@ -217,12 +226,36 @@ dns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int interval); * Set the periodic cache cleaning interval to 'interval' seconds. */ +unsigned int +dns_cache_getcleaninginterval(dns_cache_t *cache); +/*%< + * Get the periodic cache cleaning interval to 'interval' seconds. + */ + +isc_uint32_t +dns_cache_getcachesize(dns_cache_t *cache); +/*%< + * Get the maximum cache size. + */ + +const char * +dns_cache_getname(dns_cache_t *cache); +/*%< + * Get the cache name. + */ + void dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size); /*%< * Set the maximum cache size. 0 means unlimited. */ +isc_uint32_t +dns_cache_getcachesize(dns_cache_t *cache); +/*%< + * Get the maximum cache size. + */ + isc_result_t dns_cache_flush(dns_cache_t *cache); /*%< diff --git a/lib/dns/include/dns/client.h b/lib/dns/include/dns/client.h new file mode 100644 index 0000000..13cdf8f --- /dev/null +++ b/lib/dns/include/dns/client.h @@ -0,0 +1,621 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: client.h,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +#ifndef DNS_CLIENT_H +#define DNS_CLIENT_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file + * + * \brief + * The DNS client module provides convenient programming interfaces to various + * DNS services, such as name resolution with or without DNSSEC validation or + * dynamic DNS update. This module is primarily expected to be used by other + * applications than BIND9-related ones that need such advanced DNS features. + * + * MP: + *\li In the typical usage of this module, application threads will not share + * the same data structures created and manipulated in this module. + * However, the module still ensures appropriate synchronization of such + * data structures. + * + * Resources: + *\li TBS + * + * Security: + *\li This module does not handle any low-level data directly, and so no + * security issue specific to this module is anticipated. + */ + +#include +#include + +#include +#include + +#include + +typedef enum { + updateop_none = 0, + updateop_add = 1, + updateop_delete = 2, + updateop_exist = 3, + updateop_notexist = 4, + updateop_max = 5 +} dns_client_updateop_t; + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +/*% + * Optional flags for dns_client_create(x). + */ +/*%< Enable caching resolution results (experimental). */ +#define DNS_CLIENTCREATEOPT_USECACHE 0x8000 + +/*% + * Optional flags for dns_client_(start)resolve. + */ +/*%< Disable DNSSEC validation. */ +#define DNS_CLIENTRESOPT_NODNSSEC 0x01 +/*%< Allow running external context. */ +#define DNS_CLIENTRESOPT_ALLOWRUN 0x02 + +/*% + * Optional flags for dns_client_(start)request. + */ +/*%< Allow running external context. */ +#define DNS_CLIENTREQOPT_ALLOWRUN 0x01 + +/*% + * A dns_clientresevent_t is sent when name resolution performed by a client + * completes. 'result' stores the result code of the entire resolution + * procedure. 'vresult' specifically stores the result code of DNSSEC + * validation if it is performed. When name resolution successfully completes, + * 'answerlist' is typically non empty, containing answer names along with + * RRsets. It is the receiver's responsibility to free this list by calling + * dns_client_freeresanswer() before freeing the event structure. + */ +typedef struct dns_clientresevent { + ISC_EVENT_COMMON(struct dns_clientresevent); + isc_result_t result; + isc_result_t vresult; + dns_namelist_t answerlist; +} dns_clientresevent_t; /* too long? */ + +/*% + * Status of a dynamic update procedure. + */ +typedef enum { + dns_clientupdatestate_prepare, /*%< no updates have been sent */ + dns_clientupdatestate_sent, /*%< updates were sent, no response */ + dns_clientupdatestate_done /*%< update was sent and succeeded */ +} dns_clientupdatestate_t; + +/*% + * A dns_clientreqevent_t is sent when a DNS request is completed by a client. + * 'result' stores the result code of the entire transaction. + * If the transaction is successfully completed but the response packet cannot + * be parsed, 'result' will store the result code of dns_message_parse(). + * If the response packet is received, 'rmessage' will contain the response + * message, whether it is successfully parsed or not. + */ +typedef struct dns_clientreqevent { + ISC_EVENT_COMMON(struct dns_clientreqevent); + isc_result_t result; + dns_message_t *rmessage; +} dns_clientreqevent_t; /* too long? */ + +/*% + * A dns_clientupdateevent_t is sent when dynamic update performed by a client + * completes. 'result' stores the result code of the entire update procedure. + * 'state' specifies the status of the update procedure when this event is + * sent. This can be used as a hint by the receiver to determine whether + * the update attempt was ever made. In particular, if the state is + * dns_clientupdatestate_prepare, the receiver can be sure that the requested + * update was not applied. + */ +typedef struct dns_clientupdateevent { + ISC_EVENT_COMMON(struct dns_clientupdateevent); + isc_result_t result; + dns_clientupdatestate_t state; +} dns_clientupdateevent_t; /* too long? */ + +isc_result_t +dns_client_create(dns_client_t **clientp, unsigned int options); + +isc_result_t +dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, + isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, + unsigned int options, dns_client_t **clientp); +/*%< + * Create a DNS client. These functions create a new client object with + * minimal internal resources such as the default 'view' for the IN class and + * IPv4/IPv6 dispatches for the view. + * + * dns_client_createx() takes 'manager' arguments so that the caller can + * control the behavior of the client through the underlying event framework. + * On the other hand, dns_client_create() simplifies the interface and creates + * the managers internally. A DNS client object created via + * dns_client_create() is expected to be used by an application that only needs + * simple synchronous services or by a thread-based application. + * + * If the DNS_CLIENTCREATEOPT_USECACHE flag is set in 'options', + * dns_client_create(x) will create a cache database with the view. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'actx' is a valid application context. + * + *\li 'taskmgr' is a valid task manager. + * + *\li 'socketmgr' is a valid socket manager. + * + *\li 'timermgr' is a valid timer manager. + * + *\li clientp != NULL && *clientp == NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +void +dns_client_destroy(dns_client_t **clientp); +/*%< + * Destroy 'client'. + * + * Requires: + * + *\li '*clientp' is a valid client. + * + * Ensures: + * + *\li *clientp == NULL. + */ + +isc_result_t +dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass, + dns_name_t *namespace, isc_sockaddrlist_t *addrs); +/*%< + * Specify a list of addresses of recursive name servers that the client will + * use for name resolution. A view for the 'rdclass' class must be created + * beforehand. If 'namespace' is non NULL, the specified server will be used + * if and only if the query name is a subdomain of 'namespace'. When servers + * for multiple 'namespace's are provided, and a query name is covered by + * more than one 'namespace', the servers for the best (longest) matching + * namespace will be used. If 'namespace' is NULL, it works as if + * dns_rootname (.) were specified. + * + * Requires: + * + *\li 'client' is a valid client. + * + *\li 'namespace' is NULL or a valid name. + * + *\li 'addrs' != NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +isc_result_t +dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass, + dns_name_t *namespace); +/*%< + * Remove configured recursive name servers for the 'rdclass' and 'namespace' + * from the client. See the description of dns_client_setservers() for + * the requirements about 'rdclass' and 'namespace'. + * + * Requires: + * + *\li 'client' is a valid client. + * + *\li 'namespace' is NULL or a valid name. + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +isc_result_t +dns_client_resolve(dns_client_t *client, dns_name_t *name, + dns_rdataclass_t rdclass, dns_rdatatype_t type, + unsigned int options, dns_namelist_t *namelist); + +isc_result_t +dns_client_startresolve(dns_client_t *client, dns_name_t *name, + dns_rdataclass_t rdclass, dns_rdatatype_t type, + unsigned int options, isc_task_t *task, + isc_taskaction_t action, void *arg, + dns_clientrestrans_t **transp); +/*%< + * Perform name resolution for 'name', 'rdclass', and 'type'. + * + * If any trusted keys are configured and the query name is considered to + * belong to a secure zone, these functions also validate the responses + * using DNSSEC by default. If the DNS_CLIENTRESOPT_NODNSSEC flag is set + * in 'options', DNSSEC validation is disabled regardless of the configured + * trusted keys or the query name. + * + * dns_client_resolve() provides a synchronous service. This function starts + * name resolution internally and blocks until it completes. On success, + * 'namelist' will contain a list of answer names, each of which has + * corresponding RRsets. The caller must provide a valid empty list, and + * is responsible for freeing the list content via dns_client_freeresanswer(). + * If the name resolution fails due to an error in DNSSEC validation, + * dns_client_resolve() returns the result code indicating the validation + * error. Otherwise, it returns the result code of the entire resolution + * process, either success or failure. + * + * It is typically expected that the client object passed to + * dns_client_resolve() was created via dns_client_create() and has its own + * managers and contexts. However, if the DNS_CLIENTRESOPT_ALLOWRUN flag is + * set in 'options', this function performs the synchronous service even if + * it does not have its own manager and context structures. + * + * dns_client_startresolve() is an asynchronous version of dns_client_resolve() + * and does not block. When name resolution is completed, 'action' will be + * called with the argument of a 'dns_clientresevent_t' object, which contains + * the resulting list of answer names (on success). On return, '*transp' is + * set to an opaque transaction ID so that the caller can cancel this + * resolution process. + * + * Requires: + * + *\li 'client' is a valid client. + * + *\li 'addrs' != NULL. + * + *\li 'name' is a valid name. + * + *\li 'namelist' != NULL and is not empty. + * + *\li 'task' is a valid task. + * + *\li 'transp' != NULL && *transp == NULL; + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +void +dns_client_cancelresolve(dns_clientrestrans_t *trans); +/*%< + * Cancel an ongoing resolution procedure started via + * dns_client_startresolve(). + * + * Notes: + * + *\li If the resolution procedure has not completed, post its CLIENTRESDONE + * event with a result code of #ISC_R_CANCELED. + * + * Requires: + * + *\li 'trans' is a valid transaction ID. + */ + +void +dns_client_destroyrestrans(dns_clientrestrans_t **transp); +/*%< + * Destroy name resolution transaction state identified by '*transp'. + * + * Requires: + * + *\li '*transp' is a valid transaction ID. + * + *\li The caller has received the CLIENTRESDONE event (either because the + * resolution completed or because dns_client_cancelresolve() was called). + * + * Ensures: + * + *\li *transp == NULL. + */ + +void +dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist); +/*%< + * Free resources allocated for the content of 'namelist'. + * + * Requires: + * + *\li 'client' is a valid client. + * + *\li 'namelist' != NULL. + */ + +isc_result_t +dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass, + dns_name_t *keyname, isc_buffer_t *keydatabuf); +/*%< + * Add a DNSSEC trusted key for the 'rdclass' class. A view for the 'rdclass' + * class must be created beforehand. 'keyname' is the DNS name of the key, + * and 'keydatabuf' stores the resource data of the key. + * + * Requires: + * + *\li 'client' is a valid client. + * + *\li 'keyname' is a valid name. + * + *\li 'keydatabuf' is a valid buffer. + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +isc_result_t +dns_client_request(dns_client_t *client, dns_message_t *qmessage, + dns_message_t *rmessage, isc_sockaddr_t *server, + unsigned int options, unsigned int parseoptions, + dns_tsec_t *tsec, unsigned int timeout, + unsigned int udptimeout, unsigned int udpretries); + +isc_result_t +dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage, + dns_message_t *rmessage, isc_sockaddr_t *server, + unsigned int options, unsigned int parseoptions, + dns_tsec_t *tsec, unsigned int timeout, + unsigned int udptimeout, unsigned int udpretries, + isc_task_t *task, isc_taskaction_t action, void *arg, + dns_clientreqtrans_t **transp); + +/*%< + * Send a DNS request containig a query message 'query' to 'server'. + * + * 'parseoptions' will be used when the response packet is parsed, and will be + * passed to dns_message_parse() via dns_request_getresponse(). See + * dns_message_parse() for more details. + * + * 'tsec' is a transaction security object containing, e.g. a TSIG key for + * authenticating the request/response transaction. This is optional and can + * be NULL, in which case this library performs the transaction without any + * transaction authentication. + * + * 'timeout', 'udptimeout', and 'udpretries' are passed to + * dns_request_createvia3(). See dns_request_createvia3() for more details. + * + * dns_client_request() provides a synchronous service. This function sends + * the request and blocks until a response is received. On success, + * 'rmessage' will contain the response message. The caller must provide a + * valid initialized message. + * + * It is usually expected that the client object passed to + * dns_client_request() was created via dns_client_create() and has its own + * managers and contexts. However, if the DNS_CLIENTREQOPT_ALLOWRUN flag is + * set in 'options', this function performs the synchronous service even if + * it does not have its own manager and context structures. + * + * dns_client_startrequest() is an asynchronous version of dns_client_request() + * and does not block. When the transaction is completed, 'action' will be + * called with the argument of a 'dns_clientreqevent_t' object, which contains + * the response message (on success). On return, '*transp' is set to an opaque + * transaction ID so that the caller can cancel this request. + * + * Requires: + * + *\li 'client' is a valid client. + * + *\li 'qmessage' and 'rmessage' are valid initialized message. + * + *\li 'server' is a valid socket address structure. + * + *\li 'task' is a valid task. + * + *\li 'transp' != NULL && *transp == NULL; + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + * + *\li Any result that dns_message_parse() can return. + */ + +void +dns_client_cancelrequest(dns_clientreqtrans_t *transp); +/*%< + * Cancel an ongoing DNS request procedure started via + * dns_client_startrequest(). + * + * Notes: + * + *\li If the request procedure has not completed, post its CLIENTREQDONE + * event with a result code of #ISC_R_CANCELED. + * + * Requires: + * + *\li 'trans' is a valid transaction ID. + */ + +void +dns_client_destroyreqtrans(dns_clientreqtrans_t **transp); +/*% + * Destroy DNS request transaction state identified by '*transp'. + * + * Requires: + * + *\li '*transp' is a valid transaction ID. + * + *\li The caller has received the CLIENTREQDONE event (either because the + * request completed or because dns_client_cancelrequest() was called). + * + * Ensures: + * + *\li *transp == NULL. + */ + +isc_result_t +dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass, + dns_name_t *zonename, dns_namelist_t *prerequisites, + dns_namelist_t *updates, isc_sockaddrlist_t *servers, + dns_tsec_t *tsec, unsigned int options); + +isc_result_t +dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass, + dns_name_t *zonename, dns_namelist_t *prerequisites, + dns_namelist_t *updates, isc_sockaddrlist_t *servers, + dns_tsec_t *tsec, unsigned int options, + isc_task_t *task, isc_taskaction_t action, void *arg, + dns_clientupdatetrans_t **transp); +/*%< + * Perform DNS dynamic update for 'updates' of the 'rdclass' class with + * optional 'prerequisites'. + * + * 'updates' are a list of names with associated RRsets to be updated. + * + * 'prerequisites' are a list of names with associated RRsets corresponding to + * the prerequisites of the updates. This is optional and can be NULL, in + * which case the prerequisite section of the update message will be empty. + * + * Both 'updates' and 'prerequisites' must be constructed as specified in + * RFC2136. + * + * 'zonename' is the name of the zone in which the updated names exist. + * This is optional and can be NULL. In this case, these functions internally + * identify the appropriate zone through some queries for the SOA RR starting + * with the first name in prerequisites or updates. + * + * 'servers' is a list of authoritative servers to which the update message + * should be sent. This is optional and can be NULL. In this case, these + * functions internally identify the appropriate primary server name and its + * addresses through some queries for the SOA RR (like the case of zonename) + * and supplemental A/AAAA queries for the server name. + * Note: The client module generally assumes the given addresses are of the + * primary server of the corresponding zone. It will work even if a secondary + * server address is specified as long as the server allows update forwarding, + * it is generally discouraged to include secondary server addresses unless + * there's strong reason to do so. + * + * 'tsec' is a transaction security object containing, e.g. a TSIG key for + * authenticating the update transaction (and the supplemental query/response + * transactions if the server is specified). This is optional and can be + * NULL, in which case the library tries the update without any transaction + * authentication. + * + * dns_client_update() provides a synchronous service. This function blocks + * until the entire update procedure completes, including the additional + * queries when necessary. + * + * dns_client_startupdate() is an asynchronous version of dns_client_update(). + * It immediately returns (typically with *transp being set to a non-NULL + * pointer), and performs the update procedure through a set of internal + * events. All transactions including the additional query exchanges are + * performed as a separate event, so none of these events cause blocking + * operation. When the update procedure completes, the specified function + * 'action' will be called with the argument of a 'dns_clientupdateevent_t' + * structure. On return, '*transp' is set to an opaque transaction ID so that + * the caller can cancel this update process. + * + * Notes: + *\li No options are currently defined. + * + * Requires: + * + *\li 'client' is a valid client. + * + *\li 'updates' != NULL. + * + *\li 'task' is a valid task. + * + *\li 'transp' != NULL && *transp == NULL; + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +void +dns_client_cancelupdate(dns_clientupdatetrans_t *trans); +/*%< + * Cancel an ongoing dynamic update procedure started via + * dns_client_startupdate(). + * + * Notes: + * + *\li If the update procedure has not completed, post its UPDATEDONE + * event with a result code of #ISC_R_CANCELED. + * + * Requires: + * + *\li 'trans' is a valid transaction ID. + */ + +void +dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp); +/*%< + * Destroy dynamic update transaction identified by '*transp'. + * + * Requires: + * + *\li '*transp' is a valid transaction ID. + * + *\li The caller has received the UPDATEDONE event (either because the + * update completed or because dns_client_cancelupdate() was called). + * + * Ensures: + * + *\li *transp == NULL. + */ + +isc_result_t +dns_client_updaterec(dns_client_updateop_t op, dns_name_t *owner, + dns_rdatatype_t type, dns_rdata_t *source, + dns_ttl_t ttl, dns_name_t *target, + dns_rdataset_t *rdataset, dns_rdatalist_t *rdatalist, + dns_rdata_t *rdata, isc_mem_t *mctx); +/*%< + * TBD + */ + +void +dns_client_freeupdate(dns_name_t **namep); +/*%< + * TBD + */ + +isc_mem_t * +dns_client_mctx(dns_client_t *client); + +ISC_LANG_ENDDECLS + +#endif /* DNS_CLIENT_H */ diff --git a/lib/dns/include/dns/compress.h b/lib/dns/include/dns/compress.h index 4181c77..ebe543b 100644 --- a/lib/dns/include/dns/compress.h +++ b/lib/dns/include/dns/compress.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: compress.h,v 1.40.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: compress.h,v 1.42 2009-01-17 23:47:43 tbox Exp $ */ #ifndef DNS_COMPRESS_H #define DNS_COMPRESS_H 1 diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index f622834..edb1263 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: db.h,v 1.93.50.5 2009-11-25 23:48:42 tbox Exp $ */ +/* $Id: db.h,v 1.104 2011-01-13 04:59:25 tbox Exp $ */ #ifndef DNS_DB_H #define DNS_DB_H 1 @@ -59,7 +59,11 @@ #include #include +#include #include +#include +#include +#include #include ISC_LANG_BEGINDECLS @@ -167,6 +171,13 @@ typedef struct dns_dbmethods { dns_dbversion_t *version); isc_boolean_t (*isdnssec)(dns_db_t *db); dns_stats_t *(*getrrsetstats)(dns_db_t *db); + void (*rpz_enabled)(dns_db_t *db, dns_rpz_st_t *st); + isc_result_t (*rpz_findips)(dns_rpz_zone_t *rpz, + dns_rpz_type_t rpz_type, + dns_zone_t *zone, dns_db_t *db, + dns_dbversion_t *version, + dns_rdataset_t *ardataset, + dns_rpz_st_t *st); } dns_dbmethods_t; typedef isc_result_t @@ -491,6 +502,10 @@ dns_db_load(dns_db_t *db, const char *filename); isc_result_t dns_db_load2(dns_db_t *db, const char *filename, dns_masterformat_t format); + +isc_result_t +dns_db_load3(dns_db_t *db, const char *filename, dns_masterformat_t format, + unsigned int options); /*%< * Load master file 'filename' into 'db'. * @@ -614,7 +629,7 @@ dns_db_closeversion(dns_db_t *db, dns_dbversion_t **versionp, * * Note: if '*versionp' is a read-write version and 'commit' is ISC_TRUE, * then all changes made in the version will take effect, otherwise they - * will be rolled back. The value if 'commit' is ignored for read-only + * will be rolled back. The value of 'commit' is ignored for read-only * versions. * * Requires: @@ -841,6 +856,9 @@ dns_db_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, * \li #DNS_R_COVERINGNSEC The returned data is a NSEC * that potentially covers 'name'. * + * \li #DNS_R_EMPTYWILD The name is a wildcard without + * resource records. + * * Error results: * * \li #ISC_R_NOMEMORY @@ -1477,6 +1495,31 @@ dns_db_getrrsetstats(dns_db_t *db); * dns_rdatasetstats_create(); otherwise NULL. */ +void +dns_db_rpz_enabled(dns_db_t *db, dns_rpz_st_t *st); +/*%< + * See if a policy database has DNS_RPZ_TYPE_IP, DNS_RPZ_TYPE_NSIP, or + * DNS_RPZ_TYPE_NSDNAME records. + */ + +isc_result_t +dns_db_rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type, + dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, + dns_rdataset_t *ardataset, dns_rpz_st_t *st); +/*%< + * Search the CDIR block tree of a response policy tree of trees for the best + * match to any of the IP addresses in an A or AAAA rdataset. + * + * Requires: + * \li search in policy zone 'rpz' for a match of 'rpz_type' either + * DNS_RPZ_TYPE_IP or DNS_RPZ_TYPE_NSIP + * \li 'zone' and 'db' are the database corresponding to 'rpz' + * \li 'version' is the required version of the database + * \li 'ardataset' is an A or AAAA rdataset of addresses to check + * \li 'found' specifies the previous best match if any or + * or NULL, an empty name, 0, DNS_RPZ_POLICY_MISS, and 0 + */ + ISC_LANG_ENDDECLS #endif /* DNS_DB_H */ diff --git a/lib/dns/include/dns/diff.h b/lib/dns/include/dns/diff.h index f5e25ee..b6c929f 100644 --- a/lib/dns/include/dns/diff.h +++ b/lib/dns/include/dns/diff.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: diff.h,v 1.15.120.4 2010-06-04 23:48:25 tbox Exp $ */ +/* $Id: diff.h,v 1.19 2010-06-04 23:51:14 tbox Exp $ */ #ifndef DNS_DIFF_H #define DNS_DIFF_H 1 diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 6e2f3e1..3d252a1 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dispatch.h,v 1.60.82.2 2009-01-29 23:47:44 tbox Exp $ */ +/* $Id: dispatch.h,v 1.62 2009-01-27 23:47:54 tbox Exp $ */ #ifndef DNS_DISPATCH_H #define DNS_DISPATCH_H 1 diff --git a/lib/dns/include/dns/dlz.h b/lib/dns/include/dns/dlz.h index 28a24a9..e04b1b1 100644 --- a/lib/dns/include/dns/dlz.h +++ b/lib/dns/include/dns/dlz.h @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2005-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2005-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -50,7 +50,7 @@ * USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dlz.h,v 1.7.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: dlz.h,v 1.12 2010-12-20 23:47:21 tbox Exp $ */ /*! \file dns/dlz.h */ @@ -87,6 +87,7 @@ #include #include #include +#include #include @@ -166,12 +167,37 @@ typedef isc_result_t * return a result code indicating the type of error. */ + +typedef isc_result_t +(*dns_dlzconfigure_t)(void *driverarg, void *dbdata, dns_view_t *view); +/*%< + * Method prototype. Drivers implementing the DLZ interface may + * optionally supply a configure method. If supplied, this will be + * called immediately after the create method is called. The driver + * may call configuration functions during the configure call + */ + + +typedef isc_boolean_t (*dns_dlzssumatch_t)(dns_name_t *signer, + dns_name_t *name, + isc_netaddr_t *tcpaddr, + dns_rdatatype_t type, + const dst_key_t *key, + void *driverarg, void *dbdata); +/*%< + * Method prototype. Drivers implementing the DLZ interface may + * optionally supply a ssumatch method. If supplied, this will be + * called to authorize update requests + */ + /*% the methods supplied by a DLZ driver */ typedef struct dns_dlzmethods { dns_dlzcreate_t create; dns_dlzdestroy_t destroy; dns_dlzfindzone_t findzone; dns_dlzallowzonexfr_t allowzonexfr; + dns_dlzconfigure_t configure; + dns_dlzssumatch_t ssumatch; } dns_dlzmethods_t; /*% information about a DLZ driver */ @@ -183,12 +209,18 @@ struct dns_dlzimplementation { ISC_LINK(dns_dlzimplementation_t) link; }; -/*% an instance of a DLZ driver */ +typedef isc_result_t (*dlzconfigure_callback_t)(dns_view_t *, dns_zone_t *); + +/*% An instance of a DLZ driver */ struct dns_dlzdb { unsigned int magic; isc_mem_t *mctx; dns_dlzimplementation_t *implementation; void *dbdata; + dlzconfigure_callback_t configure_callback; +#ifdef BIND9 + dns_ssutable_t *ssutable; +#endif }; @@ -285,6 +317,30 @@ dns_dlzunregister(dns_dlzimplementation_t **dlzimp); * is called. */ + +isc_result_t +dns_dlz_writeablezone(dns_view_t *view, const char *zone_name); + +/*%< + * creates a writeable DLZ zone. Must be called from within the + * configure() method of a DLZ driver. + */ + + +isc_result_t +dns_dlzconfigure(dns_view_t *view, dlzconfigure_callback_t callback); +/*%< + * call a DLZ drivers configure method, if supplied + */ + +isc_boolean_t +dns_dlz_ssumatch(dns_dlzdb_t *dlzdatabase, + dns_name_t *signer, dns_name_t *name, isc_netaddr_t *tcpaddr, + dns_rdatatype_t type, const dst_key_t *key); +/*%< + * call a DLZ drivers ssumatch method, if supplied. Otherwise return ISC_FALSE + */ + ISC_LANG_ENDDECLS #endif /* DLZ_H */ diff --git a/lib/dns/include/dns/dns64.h b/lib/dns/include/dns/dns64.h new file mode 100644 index 0000000..5fd32e8 --- /dev/null +++ b/lib/dns/include/dns/dns64.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: dns64.h,v 1.3 2010-12-08 23:51:56 tbox Exp $ */ + +#ifndef DNS_DNS64_H +#define DNS_DNS64_H 1 + +#include + +#include + +ISC_LANG_BEGINDECLS + +/* + * dns_dns64_create() flags. + */ +#define DNS_DNS64_RECURSIVE_ONLY 0x01 /* If set then this record + * only applies to recursive + * queries. + */ +#define DNS_DNS64_BREAK_DNSSEC 0x02 /* If set then still perform + * DNSSEC synthesis even + * though the result would + * fail validation. + */ + +/* + * dns_dns64_aaaaok() and dns_dns64_aaaafroma() flags. + */ +#define DNS_DNS64_RECURSIVE 0x01 /* Recursive query. */ +#define DNS_DNS64_DNSSEC 0x02 /* DNSSEC sensitive query. */ + +isc_result_t +dns_dns64_create(isc_mem_t *mctx, isc_netaddr_t *prefix, + unsigned int prefixlen, isc_netaddr_t *suffix, + dns_acl_t *client, dns_acl_t *mapped, dns_acl_t *excluded, + unsigned int flags, dns_dns64_t **dns64); +/* + * Create a dns64 record which is used to identify the set of clients + * it applies to and how to perform the DNS64 synthesis. + * + * 'prefix' and 'prefixlen' defined the leading bits of the AAAA records + * to be synthesised. 'suffix' defines the bits after the A records bits. + * If suffix is NULL zeros will be used for these bits. 'client' defines + * for which clients this record applies. If 'client' is NULL then all + * clients apply. 'mapped' defines which A records are candidated for + * mapping. If 'mapped' is NULL then all A records will be mapped. + * 'excluded' defines which AAAA are to be treated as non-existent for the + * purposed of determining whether to perform syntesis. If 'excluded' is + * NULL then no AAAA records prevent synthesis. + * + * If DNS_DNS64_RECURSIVE_ONLY is set then the record will only match if + * DNS_DNS64_RECURSIVE is set when calling dns_dns64_aaaaok() and + * dns_dns64_aaaafroma(). + * + * If DNS_DNS64_BREAK_DNSSEC is set then the record will still apply if + * DNS_DNS64_DNSSEC is set when calling dns_dns64_aaaaok() and + * dns_dns64_aaaafroma() otherwise the record will be ignored. + * + * Requires: + * 'mctx' to be valid. + * 'prefix' to be valid and the address family to AF_INET6. + * 'prefixlen' to be one of 32, 40, 48, 56, 72 and 96. + * the bits not covered by prefixlen in prefix to + * be zero. + * 'suffix' to be NULL or the address family be set to AF_INET6 + * and the leading 'prefixlen' + 32 bits of the 'suffix' + * to be zero. If 'prefixlen' is 40, 48 or 56 then the + * the leading 'prefixlen' + 40 bits of 'suffix' must be + * zero. + * 'client' to be NULL or a valid acl. + * 'mapped' to be NULL or a valid acl. + * 'exculded' to be NULL or a valid acl. + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOMEMORY + */ + +void +dns_dns64_destroy(dns_dns64_t **dns64p); +/* + * Destroys a dns64 record. + * + * Requires the record to not be linked. + */ + +isc_result_t +dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, + const dns_name_t *reqsigner, const dns_aclenv_t *env, + unsigned int flags, unsigned char *a, unsigned char *aaaa); +/* + * dns_dns64_aaaafroma() determines whether to perform a DNS64 address + * synthesis from 'a' based on 'dns64', 'reqaddr', 'reqsigner', 'env', + * 'flags' and 'aaaa'. If synthesis is performed then the result is + * written to '*aaaa'. + * + * The synthesised address will be of the form: + * + * + * + * If straddle bits 64-71 of the AAAA record, then 8 zero bits will + * be inserted at bits 64-71. + * + * Requires: + * 'dns64' to be valid. + * 'reqaddr' to be valid. + * 'reqsigner' to be NULL or valid. + * 'env' to be valid. + * 'a' to point to a IPv4 address in network order. + * 'aaaa' to point to a IPv6 address buffer in network order. + * + * Returns: + * ISC_R_SUCCESS if synthesis was performed. + * DNS_R_DISALLOWED if there is no match. + */ + +dns_dns64_t * +dns_dns64_next(dns_dns64_t *dns64); +/* + * Return the next dns64 record in the list. + */ + +void +dns_dns64_append(dns_dns64list_t *list, dns_dns64_t *dns64); +/* + * Append the dns64 record to the list. + */ + +void +dns_dns64_unlink(dns_dns64list_t *list, dns_dns64_t *dns64); +/* + * Unlink the dns64 record from the list. + */ + +isc_boolean_t +dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, + const dns_name_t *reqsigner, const dns_aclenv_t *env, + unsigned int flags, dns_rdataset_t *rdataset, + isc_boolean_t *aaaaok, size_t aaaaoklen); +/* + * Determine if there are any non-excluded AAAA records in from the + * matching dns64 records in the list starting at 'dns64'. If there + * is a non-exluded address return ISC_TRUE. If all addresses are + * excluded in the matched records return ISC_FALSE. If no records + * match then return ISC_TRUE. + * + * If aaaaok is defined then dns_dns64_aaaaok() return a array of which + * addresses in 'rdataset' were deemed to not be exclude by any matching + * record. If there are no matching records then all entries are set + * to ISC_TRUE. + * + * Requires + * 'rdataset' to be valid and to be for type AAAA and class IN. + * 'aaaaoklen' must match the number of records in 'rdataset' + * if 'aaaaok' in non NULL. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_DNS64_H */ diff --git a/lib/dns/include/dns/dnssec.h b/lib/dns/include/dns/dnssec.h index 5a1468a..c6d910b 100644 --- a/lib/dns/include/dns/dnssec.h +++ b/lib/dns/include/dns/dnssec.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec.h,v 1.32.332.6 2009-06-22 23:47:18 tbox Exp $ */ +/* $Id: dnssec.h,v 1.42 2010-01-09 23:48:45 tbox Exp $ */ #ifndef DNS_DNSSEC_H #define DNS_DNSSEC_H 1 @@ -25,12 +25,48 @@ #include #include +#include #include #include ISC_LANG_BEGINDECLS +/* + * Indicates how the signer found this key: in the key repository, at the + * zone apex, or specified by the user. + */ +typedef enum { + dns_keysource_unknown, + dns_keysource_repository, + dns_keysource_zoneapex, + dns_keysource_user +} dns_keysource_t; + +/* + * A DNSSEC key and hints about its intended use gleaned from metadata + */ +struct dns_dnsseckey { + dst_key_t *key; + isc_boolean_t hint_publish; /*% metadata says to publish */ + isc_boolean_t force_publish; /*% publish regardless of metadata */ + isc_boolean_t hint_sign; /*% metadata says to sign with this key */ + isc_boolean_t force_sign; /*% sign with key regardless of metadata */ + isc_boolean_t hint_remove; /*% metadata says *don't* publish */ + isc_boolean_t is_active; /*% key is already active */ + isc_boolean_t first_sign; /*% key is newly becoming active */ + unsigned int prepublish; /*% how long until active? */ + dns_keysource_t source; /*% how the key was found */ + isc_boolean_t ksk; /*% this is a key-signing key */ + isc_boolean_t legacy; /*% this is old-style key with no + metadata (possibly generated by + an older version of BIND9) and + should be ignored when searching + for keys to import into the zone */ + unsigned int index; /*% position in list */ + ISC_LINK(dns_dnsseckey_t) link; +}; + isc_result_t dns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, isc_mem_t *mctx, dst_key_t **key); @@ -184,6 +220,103 @@ dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name, isc_boolean_t ignoretime, isc_mem_t *mctx); +isc_result_t +dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey, + dns_dnsseckey_t **dkp); +/*%< + * Create and initialize a dns_dnsseckey_t structure. + * + * Requires: + *\li 'dkp' is not NULL and '*dkp' is NULL. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +void +dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp); +/*%< + * Reclaim a dns_dnsseckey_t structure. + * + * Requires: + *\li 'dkp' is not NULL and '*dkp' is not NULL. + * + * Ensures: + *\li '*dkp' is NULL. + */ + +isc_result_t +dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory, + isc_mem_t *mctx, dns_dnsseckeylist_t *keylist); +/*%< + * Search 'directory' for K* key files matching the name in 'origin'. + * Append all such keys, along with use hints gleaned from their + * metadata, onto 'keylist'. + * + * Requires: + *\li 'keylist' is not NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOTFOUND + *\li #ISC_R_NOMEMORY + *\li any error returned by dns_name_totext(), isc_dir_open(), or + * dst_key_fromnamedfile() + * + * Ensures: + *\li On error, keylist is unchanged + */ + +isc_result_t +dns_dnssec_keylistfromrdataset(dns_name_t *origin, + const char *directory, isc_mem_t *mctx, + dns_rdataset_t *keyset, dns_rdataset_t *keysigs, + dns_rdataset_t *soasigs, isc_boolean_t savekeys, + isc_boolean_t public, + dns_dnsseckeylist_t *keylist); +/*%< + * Append the contents of a DNSKEY rdataset 'keyset' to 'keylist'. + * Omit duplicates. If 'public' is ISC_FALSE, search 'directory' for + * matching key files, and load the private keys that go with + * the public ones. If 'savekeys' is ISC_TRUE, mark the keys so + * they will not be deleted or inactivated regardless of metadata. + * + * 'keysigs' and 'soasigs', if not NULL and associated, contain the + * RRSIGS for the DNSKEY and SOA records respectively and are used to mark + * whether a key is already active in the zone. + */ + +isc_result_t +dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys, + dns_dnsseckeylist_t *removed, dns_name_t *origin, + dns_ttl_t ttl, dns_diff_t *diff, isc_boolean_t allzsk, + isc_mem_t *mctx, void (*report)(const char *, ...)); +/*%< + * Update the list of keys in 'keys' with new key information in 'newkeys'. + * + * For each key in 'newkeys', see if it has a match in 'keys'. + * - If not, and if the metadata says the key should be published: + * add it to 'keys', and place a dns_difftuple into 'diff' so + * the key can be added to the DNSKEY set. If the metadata says it + * should be active, set the first_sign flag. + * - If so, and if the metadata says it should be removed: + * remove it from 'keys', and place a dns_difftuple into 'diff' so + * the key can be removed from the DNSKEY set. if 'removed' is non-NULL, + * copy the key into that list; otherwise destroy it. + * - Otherwise, make sure keys has current metadata. + * + * If 'allzsk' is true, we are allowing KSK-flagged keys to be used as + * ZSKs. + * + * 'ttl' is the TTL of the DNSKEY RRset; if it is longer than the + * time until a new key will be activated, then we have to delay the + * key's activation. + * + * 'report' points to a function for reporting status. + * + * On completion, any remaining keys in 'newkeys' are freed. + */ ISC_LANG_ENDDECLS #endif /* DNS_DNSSEC_H */ diff --git a/lib/dns/include/dns/ds.h b/lib/dns/include/dns/ds.h index 77a2cb8..04e4bab 100644 --- a/lib/dns/include/dns/ds.h +++ b/lib/dns/include/dns/ds.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ds.h,v 1.10 2007-06-19 23:47:16 tbox Exp $ */ +/* $Id: ds.h,v 1.12 2010-12-23 23:47:08 tbox Exp $ */ #ifndef DNS_DS_H #define DNS_DS_H 1 @@ -26,6 +26,11 @@ #define DNS_DSDIGEST_SHA1 (1) #define DNS_DSDIGEST_SHA256 (2) +#define DNS_DSDIGEST_GOST (3) + +/* should not be here... */ + +#define ISC_GOST_DIGESTLENGTH 32U /* * Assuming SHA-256 digest type. diff --git a/lib/dns/include/dns/ecdb.h b/lib/dns/include/dns/ecdb.h new file mode 100644 index 0000000..be71a52 --- /dev/null +++ b/lib/dns/include/dns/ecdb.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: ecdb.h,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +#ifndef DNS_ECDB_H +#define DNS_ECDB_H 1 + +/***** + ***** Module Info + *****/ + +/* TBD */ + +/*** + *** Imports + ***/ + +#include + +/*** + *** Types + ***/ + +/*** + *** Functions + ***/ + +/* TBD: describe those */ + +isc_result_t +dns_ecdb_register(isc_mem_t *mctx, dns_dbimplementation_t **dbimp); + +void +dns_ecdb_unregister(dns_dbimplementation_t **dbimp); + +ISC_LANG_ENDDECLS + +#endif /* DNS_ECDB_H */ diff --git a/lib/dns/include/dns/events.h b/lib/dns/include/dns/events.h index 689566b..d985833 100644 --- a/lib/dns/include/dns/events.h +++ b/lib/dns/include/dns/events.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: events.h,v 1.49.332.4 2010-05-10 23:48:14 tbox Exp $ */ +/* $Id: events.h,v 1.56 2010-12-21 03:11:42 marka Exp $ */ #ifndef DNS_EVENTS_H #define DNS_EVENTS_H 1 @@ -69,6 +69,11 @@ #define DNS_EVENT_ACACHECLEAN (ISC_EVENTCLASS_DNS + 39) #define DNS_EVENT_ACACHEOVERMEM (ISC_EVENTCLASS_DNS + 40) #define DNS_EVENT_RBTPRUNE (ISC_EVENTCLASS_DNS + 41) +#define DNS_EVENT_MANAGEKEYS (ISC_EVENTCLASS_DNS + 42) +#define DNS_EVENT_CLIENTRESDONE (ISC_EVENTCLASS_DNS + 43) +#define DNS_EVENT_CLIENTREQDONE (ISC_EVENTCLASS_DNS + 44) +#define DNS_EVENT_ADBGROWENTRIES (ISC_EVENTCLASS_DNS + 45) +#define DNS_EVENT_ADBGROWNAMES (ISC_EVENTCLASS_DNS + 46) #define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0) #define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535) diff --git a/lib/dns/include/dns/forward.h b/lib/dns/include/dns/forward.h index 5fbe898..683969d 100644 --- a/lib/dns/include/dns/forward.h +++ b/lib/dns/include/dns/forward.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: forward.h,v 1.11 2007-06-19 23:47:16 tbox Exp $ */ +/* $Id: forward.h,v 1.13 2009-09-02 23:48:02 tbox Exp $ */ #ifndef DNS_FORWARD_H #define DNS_FORWARD_H 1 @@ -67,6 +67,21 @@ dns_fwdtable_add(dns_fwdtable_t *fwdtable, dns_name_t *name, */ isc_result_t +dns_fwdtable_delete(dns_fwdtable_t *fwdtable, dns_name_t *name); +/*%< + * Removes an entry for 'name' from the forwarding table. If an entry + * that exactly matches 'name' does not exist, ISC_R_NOTFOUND will be returned. + * + * Requires: + * \li fwdtable is a valid forwarding table. + * \li name is a valid name + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND + */ + +isc_result_t dns_fwdtable_find(dns_fwdtable_t *fwdtable, dns_name_t *name, dns_forwarders_t **forwardersp); /*%< diff --git a/lib/dns/include/dns/journal.h b/lib/dns/include/dns/journal.h index 9e56c19..28a7dbe 100644 --- a/lib/dns/include/dns/journal.h +++ b/lib/dns/include/dns/journal.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: journal.h,v 1.33.120.4 2009-11-04 23:47:25 tbox Exp $ */ +/* $Id: journal.h,v 1.37 2009-11-04 23:48:18 tbox Exp $ */ #ifndef DNS_JOURNAL_H #define DNS_JOURNAL_H 1 diff --git a/lib/dns/include/dns/keydata.h b/lib/dns/include/dns/keydata.h new file mode 100644 index 0000000..36bf590 --- /dev/null +++ b/lib/dns/include/dns/keydata.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: keydata.h,v 1.2 2009-06-30 02:52:32 each Exp $ */ + +#ifndef DNS_KEYDATA_H +#define DNS_KEYDATA_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file dns/keydata.h + * \brief + * KEYDATA utilities. + */ + +/*** + *** Imports + ***/ + +#include +#include + +#include +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_keydata_todnskey(dns_rdata_keydata_t *keydata, + dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx); + +isc_result_t +dns_keydata_fromdnskey(dns_rdata_keydata_t *keydata, + dns_rdata_dnskey_t *dnskey, + isc_uint32_t refresh, isc_uint32_t addhd, + isc_uint32_t removehd, isc_mem_t *mctx); + +ISC_LANG_ENDDECLS + +#endif /* DNS_KEYDATA_H */ diff --git a/lib/dns/include/dns/keytable.h b/lib/dns/include/dns/keytable.h index 40c4b16..a53ec08 100644 --- a/lib/dns/include/dns/keytable.h +++ b/lib/dns/include/dns/keytable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: keytable.h,v 1.16 2007-06-19 23:47:16 tbox Exp $ */ +/* $Id: keytable.h,v 1.23 2010-06-25 03:24:05 marka Exp $ */ #ifndef DNS_KEYTABLE_H #define DNS_KEYTABLE_H 1 @@ -42,6 +42,10 @@ */ #include +#include +#include +#include +#include #include @@ -49,6 +53,33 @@ ISC_LANG_BEGINDECLS +struct dns_keytable { + /* Unlocked. */ + unsigned int magic; + isc_mem_t *mctx; + isc_mutex_t lock; + isc_rwlock_t rwlock; + /* Locked by lock. */ + isc_uint32_t active_nodes; + /* Locked by rwlock. */ + isc_uint32_t references; + dns_rbt_t *table; +}; + +#define KEYTABLE_MAGIC ISC_MAGIC('K', 'T', 'b', 'l') +#define VALID_KEYTABLE(kt) ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC) + +struct dns_keynode { + unsigned int magic; + isc_refcount_t refcount; + dst_key_t * key; + isc_boolean_t managed; + struct dns_keynode * next; +}; + +#define KEYNODE_MAGIC ISC_MAGIC('K', 'N', 'o', 'd') +#define VALID_KEYNODE(kn) ISC_MAGIC_VALID(kn, KEYNODE_MAGIC) + isc_result_t dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep); /*%< @@ -106,16 +137,22 @@ dns_keytable_detach(dns_keytable_t **keytablep); */ isc_result_t -dns_keytable_add(dns_keytable_t *keytable, dst_key_t **keyp); +dns_keytable_add(dns_keytable_t *keytable, isc_boolean_t managed, + dst_key_t **keyp); /*%< - * Add '*keyp' to 'keytable'. + * Add '*keyp' to 'keytable' (using the name in '*keyp'). + * The value of keynode->managed is set to 'managed' * * Notes: * *\li Ownership of *keyp is transferred to the keytable. + *\li If the key already exists in the table, ISC_R_EXISTS is + * returned and the new key is freed. * * Requires: * + *\li 'keytable' points to a valid keytable. + * *\li keyp != NULL && *keyp is a valid dst_key_t *. * * Ensures: @@ -125,11 +162,124 @@ dns_keytable_add(dns_keytable_t *keytable, dst_key_t **keyp); * Returns: * *\li ISC_R_SUCCESS + *\li ISC_R_EXISTS + * + *\li Any other result indicates failure. + */ + +isc_result_t +dns_keytable_marksecure(dns_keytable_t *keytable, dns_name_t *name); +/*%< + * Add a null key to 'keytable' for name 'name'. This marks the + * name as a secure domain, but doesn't supply any key data to allow the + * domain to be validated. (Used when automated trust anchor management + * has gotten broken by a zone misconfiguration; for example, when the + * active key has been revoked but the stand-by key was still in its 30-day + * waiting period for validity.) + * + * Notes: + * + *\li If a key already exists in the table, ISC_R_EXISTS is + * returned and nothing is done. + * + * Requires: + * + *\li 'keytable' points to a valid keytable. + * + *\li keyp != NULL && *keyp is a valid dst_key_t *. + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li ISC_R_EXISTS + * + *\li Any other result indicates failure. + */ + +isc_result_t +dns_keytable_delete(dns_keytable_t *keytable, dns_name_t *keyname); +/*%< + * Delete node(s) from 'keytable' matching name 'keyname' + * + * Requires: + * + *\li 'keytable' points to a valid keytable. + * + *\li 'name' is not NULL + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Any other result indicates failure. + */ + +isc_result_t +dns_keytable_deletekeynode(dns_keytable_t *keytable, dst_key_t *dstkey); +/*%< + * Delete node(s) from 'keytable' containing copies of the key pointed + * to by 'dstkey' + * + * Requires: + * + *\li 'keytable' points to a valid keytable. + *\li 'dstkey' is not NULL + * + * Returns: + * + *\li ISC_R_SUCCESS * *\li Any other result indicates failure. */ isc_result_t +dns_keytable_find(dns_keytable_t *keytable, dns_name_t *keyname, + dns_keynode_t **keynodep); +/*%< + * Search for the first instance of a key named 'name' in 'keytable', + * without regard to keyid and algorithm. Use dns_keytable_nextkeynode() + * to find subsequent instances. + * + * Requires: + * + *\li 'keytable' is a valid keytable. + * + *\li 'name' is a valid absolute name. + * + *\li keynodep != NULL && *keynodep == NULL + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li ISC_R_NOTFOUND + * + *\li Any other result indicates an error. + */ + +isc_result_t +dns_keytable_nextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode, + dns_keynode_t **nextnodep); +/*%< + * Return for the next key after 'keynode' in 'keytable', without regard to + * keyid and algorithm. + * + * Requires: + * + *\li 'keytable' is a valid keytable. + * + *\li 'keynode' is a valid keynode. + * + *\li nextnodep != NULL && *nextnodep == NULL + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li ISC_R_NOTFOUND + * + *\li Any other result indicates an error. + */ + +isc_result_t dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name, dns_secalg_t algorithm, dns_keytag_t tag, dns_keynode_t **keynodep); @@ -157,7 +307,7 @@ dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name, isc_result_t dns_keytable_findnextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode, - dns_keynode_t **nextnodep); + dns_keynode_t **nextnodep); /*%< * Search for the next key with the same properties as 'keynode' in * 'keytable' as found by dns_keytable_findkeynode(). @@ -201,6 +351,22 @@ dns_keytable_finddeepestmatch(dns_keytable_t *keytable, dns_name_t *name, */ void +dns_keytable_attachkeynode(dns_keytable_t *keytable, dns_keynode_t *source, + dns_keynode_t **target); +/*%< + * Attach a keynode and and increment the active_nodes counter in a + * corresponding keytable. + * + * Requires: + * + *\li 'keytable' is a valid keytable. + * + *\li 'source' is a valid keynode. + * + *\li 'target' is not null and '*target' is null. + */ + +void dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep); /*%< @@ -244,12 +410,48 @@ dns_keytable_issecuredomain(dns_keytable_t *keytable, dns_name_t *name, *\li Any other result is an error. */ +isc_result_t +dns_keytable_dump(dns_keytable_t *keytable, FILE *fp); +/*%< + * Dump the keytable on fp. + */ + dst_key_t * dns_keynode_key(dns_keynode_t *keynode); /*%< * Get the DST key associated with keynode. */ +isc_boolean_t +dns_keynode_managed(dns_keynode_t *keynode); +/*%< + * Is this flagged as a managed key? + */ + +isc_result_t +dns_keynode_create(isc_mem_t *mctx, dns_keynode_t **target); +/*%< + * Allocate space for a keynode + */ + +void +dns_keynode_attach(dns_keynode_t *source, dns_keynode_t **target); +/*%< + * Attach keynode 'source' to '*target' + */ + +void +dns_keynode_detach(isc_mem_t *mctx, dns_keynode_t **target); +/*%< + * Detach a single keynode, without touching any keynodes that + * may be pointed to by its 'next' pointer + */ + +void +dns_keynode_detachall(isc_mem_t *mctx, dns_keynode_t **target); +/*%< + * Detach a keynode and all its succesors. + */ ISC_LANG_ENDDECLS #endif /* DNS_KEYTABLE_H */ diff --git a/lib/dns/include/dns/keyvalues.h b/lib/dns/include/dns/keyvalues.h index 70ca3fa..2107657 100644 --- a/lib/dns/include/dns/keyvalues.h +++ b/lib/dns/include/dns/keyvalues.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: keyvalues.h,v 1.23.48.4 2010-01-15 23:47:33 tbox Exp $ */ +/* $Id: keyvalues.h,v 1.29 2010-12-23 23:47:08 tbox Exp $ */ #ifndef DNS_KEYVALUES_H #define DNS_KEYVALUES_H 1 @@ -42,7 +42,7 @@ #define DNS_KEYOWNER_ENTITY 0x0200 /*%< key is assoc. with entity eg host */ #define DNS_KEYOWNER_ZONE 0x0100 /*%< key is zone key */ #define DNS_KEYOWNER_RESERVED 0x0300 /*%< reserved meaning */ -#define DNS_KEYFLAG_REVOKE 0x0080 /*%< key revoked (per rfc5001) */ +#define DNS_KEYFLAG_REVOKE 0x0080 /*%< key revoked (per rfc5011) */ #define DNS_KEYFLAG_RESERVED9 0x0040 /*%< reserved - must be zero */ #define DNS_KEYFLAG_RESERVED10 0x0020 /*%< reserved - must be zero */ #define DNS_KEYFLAG_RESERVED11 0x0010 /*%< reserved - must be zero */ @@ -51,7 +51,6 @@ #define DNS_KEYFLAG_RESERVEDMASK (DNS_KEYFLAG_RESERVED2 | \ DNS_KEYFLAG_RESERVED4 | \ DNS_KEYFLAG_RESERVED5 | \ - DNS_KEYFLAG_RESERVED8 | \ DNS_KEYFLAG_RESERVED9 | \ DNS_KEYFLAG_RESERVED10 | \ DNS_KEYFLAG_RESERVED11 ) @@ -71,6 +70,7 @@ #define DNS_KEYALG_NSEC3RSASHA1 7 #define DNS_KEYALG_RSASHA256 8 #define DNS_KEYALG_RSASHA512 10 +#define DNS_KEYALG_ECCGOST 12 #define DNS_KEYALG_INDIRECT 252 #define DNS_KEYALG_PRIVATEDNS 253 #define DNS_KEYALG_PRIVATEOID 254 /*%< Key begins with OID giving alg */ @@ -99,4 +99,6 @@ #define DNS_SIG_DSAMINBYTES 213 #define DNS_SIG_DSAMAXBYTES 405 +#define DNS_SIG_GOSTSIGSIZE 64 + #endif /* DNS_KEYVALUES_H */ diff --git a/lib/dns/include/dns/lib.h b/lib/dns/include/dns/lib.h index 361ef8f..70874b7 100644 --- a/lib/dns/include/dns/lib.h +++ b/lib/dns/include/dns/lib.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lib.h,v 1.16 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: lib.h,v 1.18 2009-09-02 23:48:02 tbox Exp $ */ #ifndef DNS_LIB_H #define DNS_LIB_H 1 @@ -40,6 +40,20 @@ dns_lib_initmsgcat(void); * has not already been initialized. */ +isc_result_t +dns_lib_init(void); +/*%< + * A set of initialization procedure used in the DNS library. This function + * is provided for an application that is not aware of the underlying ISC or + * DNS libraries much. + */ + +void +dns_lib_shutdown(void); +/*%< + * Free temporary resources allocated in dns_lib_init(). + */ + ISC_LANG_ENDDECLS #endif /* DNS_LIB_H */ diff --git a/lib/dns/include/dns/log.h b/lib/dns/include/dns/log.h index 4b648ff..a5650ed 100644 --- a/lib/dns/include/dns/log.h +++ b/lib/dns/include/dns/log.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: log.h,v 1.42.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: log.h,v 1.45 2009-12-18 22:16:49 each Exp $ */ /*! \file dns/log.h * \author Principal Authors: DCL */ @@ -73,6 +73,7 @@ LIBDNS_EXTERNAL_DATA extern isc_logmodule_t dns_modules[]; #define DNS_LOGMODULE_HINTS (&dns_modules[24]) #define DNS_LOGMODULE_ACACHE (&dns_modules[25]) #define DNS_LOGMODULE_DLZ (&dns_modules[26]) +#define DNS_LOGMODULE_DNSSEC (&dns_modules[27]) ISC_LANG_BEGINDECLS diff --git a/lib/dns/include/dns/lookup.h b/lib/dns/include/dns/lookup.h index 81bb9b9..7e6a566 100644 --- a/lib/dns/include/dns/lookup.h +++ b/lib/dns/include/dns/lookup.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lookup.h,v 1.12.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: lookup.h,v 1.14 2009-01-17 23:47:43 tbox Exp $ */ #ifndef DNS_LOOKUP_H #define DNS_LOOKUP_H 1 diff --git a/lib/dns/include/dns/master.h b/lib/dns/include/dns/master.h index 3f3a4de..2ee6374 100644 --- a/lib/dns/include/dns/master.h +++ b/lib/dns/include/dns/master.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: master.h,v 1.51 2008-04-02 02:37:42 marka Exp $ */ +/* $Id: master.h,v 1.53 2009-07-01 23:47:36 tbox Exp $ */ #ifndef DNS_MASTER_H #define DNS_MASTER_H 1 @@ -56,6 +56,7 @@ #define DNS_MASTER_CHECKMXFAIL 0x00001000 #define DNS_MASTER_RESIGN 0x00002000 +#define DNS_MASTER_KEY 0x00004000 /*%< Loading a key zone master file. */ ISC_LANG_BEGINDECLS diff --git a/lib/dns/include/dns/masterdump.h b/lib/dns/include/dns/masterdump.h index 96a198d..684dd82 100644 --- a/lib/dns/include/dns/masterdump.h +++ b/lib/dns/include/dns/masterdump.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: masterdump.h,v 1.42.602.2 2011-06-02 23:46:22 tbox Exp $ */ +/* $Id: masterdump.h,v 1.42.596.2 2011-06-02 23:47:35 tbox Exp $ */ #ifndef DNS_MASTERDUMP_H #define DNS_MASTERDUMP_H 1 diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index 98fb321..438de1e 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: message.h,v 1.125.118.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: message.h,v 1.132 2010-03-04 23:50:34 tbox Exp $ */ #ifndef DNS_MESSAGE_H #define DNS_MESSAGE_H 1 @@ -81,8 +81,7 @@ * name = NULL; * name = dns_message_gettempname(message, &name); * dns_name_init(name, NULL); - * result = dns_name_fromtext(name, &source, dns_rootname, ISC_FALSE, - * buffer); + * result = dns_name_fromtext(name, &source, dns_rootname, 0, buffer); * dns_message_takebuffer(message, &buffer); * \endcode * @@ -137,6 +136,8 @@ typedef int dns_pseudosection_t; typedef int dns_messagetextflag_t; #define DNS_MESSAGETEXTFLAG_NOCOMMENTS 0x0001 #define DNS_MESSAGETEXTFLAG_NOHEADERS 0x0002 +#define DNS_MESSAGETEXTFLAG_ONESOA 0x0004 +#define DNS_MESSAGETEXTFLAG_OMITSOA 0x0008 /* * Dynamic update names for these sections. @@ -174,6 +175,9 @@ typedef int dns_messagetextflag_t; additional section. */ #define DNS_MESSAGERENDER_PREFER_AAAA 0x0010 /*%< prefer AAAA records in additional section. */ +#ifdef ALLOW_FILTER_AAAA_ON_V4 +#define DNS_MESSAGERENDER_FILTER_AAAA 0x0020 /*%< filter AAAA records */ +#endif typedef struct dns_msgblock dns_msgblock_t; @@ -369,6 +373,14 @@ dns_message_totext(dns_message_t *msg, const dns_master_style_t *style, * #DNS_MESSAGETEXTFLAG_NOHEADERS is cleared, header lines will * be emitted. * + * If #DNS_MESSAGETEXTFLAG_ONESOA is set then only print the + * first SOA record in the answer section. If + * #DNS_MESSAGETEXTFLAG_OMITSOA is set don't print any SOA records + * in the answer section. These are useful for suppressing the + * display of the second SOA record in a AXFR by setting + * #DNS_MESSAGETEXTFLAG_ONESOA on the first message in a AXFR stream + * and #DNS_MESSAGETEXTFLAG_OMITSOA on subsequent messages. + * * Requires: * *\li 'msg' is a valid message. diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h index 801c9ac..c13a85d 100644 --- a/lib/dns/include/dns/name.h +++ b/lib/dns/include/dns/name.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: name.h,v 1.126.332.5 2010-07-09 23:45:55 tbox Exp $ */ +/* $Id: name.h,v 1.137 2011-01-13 04:59:26 tbox Exp $ */ #ifndef DNS_NAME_H #define DNS_NAME_H 1 @@ -121,21 +121,27 @@ struct dns_name { #define DNS_NAME_MAGIC ISC_MAGIC('D','N','S','n') -#define DNS_NAMEATTR_ABSOLUTE 0x0001 -#define DNS_NAMEATTR_READONLY 0x0002 -#define DNS_NAMEATTR_DYNAMIC 0x0004 -#define DNS_NAMEATTR_DYNOFFSETS 0x0008 -#define DNS_NAMEATTR_NOCOMPRESS 0x0010 +#define DNS_NAMEATTR_ABSOLUTE 0x00000001 +#define DNS_NAMEATTR_READONLY 0x00000002 +#define DNS_NAMEATTR_DYNAMIC 0x00000004 +#define DNS_NAMEATTR_DYNOFFSETS 0x00000008 +#define DNS_NAMEATTR_NOCOMPRESS 0x00000010 /* * Attributes below 0x0100 reserved for name.c usage. */ -#define DNS_NAMEATTR_CACHE 0x0100 /*%< Used by resolver. */ -#define DNS_NAMEATTR_ANSWER 0x0200 /*%< Used by resolver. */ -#define DNS_NAMEATTR_NCACHE 0x0400 /*%< Used by resolver. */ -#define DNS_NAMEATTR_CHAINING 0x0800 /*%< Used by resolver. */ -#define DNS_NAMEATTR_CHASE 0x1000 /*%< Used by resolver. */ -#define DNS_NAMEATTR_WILDCARD 0x2000 /*%< Used by server. */ +#define DNS_NAMEATTR_CACHE 0x00000100 /*%< Used by resolver. */ +#define DNS_NAMEATTR_ANSWER 0x00000200 /*%< Used by resolver. */ +#define DNS_NAMEATTR_NCACHE 0x00000400 /*%< Used by resolver. */ +#define DNS_NAMEATTR_CHAINING 0x00000800 /*%< Used by resolver. */ +#define DNS_NAMEATTR_CHASE 0x00001000 /*%< Used by resolver. */ +#define DNS_NAMEATTR_WILDCARD 0x00002000 /*%< Used by server. */ +#define DNS_NAMEATTR_PREREQUISITE 0x00004000 /*%< Used by client. */ +#define DNS_NAMEATTR_UPDATE 0x00008000 /*%< Used by client. */ +#define DNS_NAMEATTR_HASUPDATEREC 0x00010000 /*%< Used by client. */ +/* + * Various flags. + */ #define DNS_NAME_DOWNCASE 0x0001 #define DNS_NAME_CHECKNAMES 0x0002 /*%< Used by rdata. */ #define DNS_NAME_CHECKNAMESFAIL 0x0004 /*%< Used by rdata. */ @@ -750,7 +756,7 @@ dns_name_towire(const dns_name_t *name, dns_compress_t *cctx, isc_result_t dns_name_fromtext(dns_name_t *name, isc_buffer_t *source, - dns_name_t *origin, unsigned int options, + const dns_name_t *origin, unsigned int options, isc_buffer_t *target); /*%< * Convert the textual representation of a DNS name at source @@ -1139,6 +1145,56 @@ dns_name_format(dns_name_t *name, char *cp, unsigned int size); */ isc_result_t +dns_name_tostring(dns_name_t *source, char **target, isc_mem_t *mctx); +/*%< + * Convert 'name' to string format, allocating sufficient memory to + * hold it (free with isc_mem_free()). + * + * Differs from dns_name_format in that it allocates its own memory. + * + * Requires: + * + *\li 'name' is a valid name. + *\li 'target' is not NULL. + *\li '*target' is NULL. + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Any error that dns_name_totext() can return. + */ + +isc_result_t +dns_name_fromstring(dns_name_t *target, const char *src, unsigned int options, + isc_mem_t *mctx); +isc_result_t +dns_name_fromstring2(dns_name_t *target, const char *src, + const dns_name_t *origin, unsigned int options, + isc_mem_t *mctx); +/*%< + * Convert a string to a name and place it in target, allocating memory + * as necessary. 'options' has the same semantics as that of + * dns_name_fromtext(). + * + * If 'target' has a buffer then the name will be copied into it rather than + * memory being allocated. + * + * Requires: + * + * \li 'target' is a valid name that is not read-only. + * \li 'src' is not NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS + * + *\li Any error that dns_name_fromtext() can return. + * + *\li Any error that dns_name_dup() can return. + */ + +isc_result_t dns_name_settotextfilter(dns_name_totextfilter_t proc); /*%< * Set / clear a thread specific function 'proc' to be called at the diff --git a/lib/dns/include/dns/ncache.h b/lib/dns/include/dns/ncache.h index 0c1d950..32345cf 100644 --- a/lib/dns/include/dns/ncache.h +++ b/lib/dns/include/dns/ncache.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ncache.h,v 1.25.48.4 2010-05-14 23:47:50 tbox Exp $ */ +/* $Id: ncache.h,v 1.29 2010-05-14 23:50:40 tbox Exp $ */ #ifndef DNS_NCACHE_H #define DNS_NCACHE_H 1 diff --git a/lib/dns/include/dns/nsec3.h b/lib/dns/include/dns/nsec3.h index ba808e4..ac0c8f2 100644 --- a/lib/dns/include/dns/nsec3.h +++ b/lib/dns/include/dns/nsec3.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2008-2010 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsec3.h,v 1.5.48.3 2009-10-06 21:20:18 each Exp $ */ +/* $Id: nsec3.h,v 1.12 2010-05-18 02:38:10 tbox Exp $ */ #ifndef DNS_NSEC3_H #define DNS_NSEC3_H 1 @@ -110,6 +110,12 @@ isc_result_t dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, dns_ttl_t nsecttl, isc_boolean_t unsecure, dns_diff_t *diff); + +isc_result_t +dns_nsec3_addnsec3sx(dns_db_t *db, dns_dbversion_t *version, + dns_name_t *name, dns_ttl_t nsecttl, + isc_boolean_t unsecure, dns_rdatatype_t private, + dns_diff_t *diff); /*%< * Add NSEC3 records for 'name', recording the change in 'diff'. * Adjust previous NSEC3 records, if any, to reflect the addition. @@ -130,6 +136,10 @@ dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version, * NSEC3PARAM record otherwise OPTOUT will be inherited from the previous * record in the chain. * + * dns_nsec3_addnsec3sx() is similar to dns_nsec3_addnsec3s() but 'private' + * specifies the type of the private rdataset to be checked in addition to + * the nsec3param rdataset at the zone apex. + * * Requires: * 'db' to be valid. * 'version' to be valid or NULL. @@ -145,6 +155,10 @@ dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, isc_result_t dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, dns_diff_t *diff); + +isc_result_t +dns_nsec3_delnsec3sx(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, + dns_rdatatype_t private, dns_diff_t *diff); /*%< * Remove NSEC3 records for 'name', recording the change in 'diff'. * Adjust previous NSEC3 records, if any, to reflect the removal. @@ -156,6 +170,10 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, * to dns_nsec3_addnsec3s(). Unlike dns_nsec3_addnsec3s() updated NSEC3 * records have the OPTOUT flag preserved. * + * dns_nsec3_delnsec3sx() is similar to dns_nsec3_delnsec3s() but 'private' + * specifies the type of the private rdataset to be checked in addition to + * the nsec3param rdataset at the zone apex. + * * Requires: * 'db' to be valid. * 'version' to be valid or NULL. @@ -167,10 +185,19 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, isc_result_t dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version, isc_boolean_t complete, isc_boolean_t *answer); + +isc_result_t +dns_nsec3_activex(dns_db_t *db, dns_dbversion_t *version, + isc_boolean_t complete, dns_rdatatype_t private, + isc_boolean_t *answer); /*%< * Check if there are any complete/to be built NSEC3 chains. * If 'complete' is ISC_TRUE only complete chains will be recognized. * + * dns_nsec3_activex() is similar to dns_nsec3_active() but 'private' + * specifies the type of the private rdataset to be checked in addition to + * the nsec3param rdataset at the zone apex. + * * Requires: * 'db' to be valid. * 'version' to be valid or NULL. @@ -191,6 +218,36 @@ dns_nsec3_maxiterations(dns_db_t *db, dns_dbversion_t *version, * 'iterationsp' to be non NULL. */ +isc_boolean_t +dns_nsec3param_fromprivate(dns_rdata_t *src, dns_rdata_t *target, + unsigned char *buf, size_t buflen); +/*%< + * Convert a private rdata to a nsec3param rdata. + * + * Return ISC_TRUE if 'src' could be successfully converted. + * + * 'buf' should be at least DNS_NSEC3PARAM_BUFFERSIZE in size. + */ + +void +dns_nsec3param_toprivate(dns_rdata_t *src, dns_rdata_t *target, + dns_rdatatype_t privatetype, + unsigned char *buf, size_t buflen); +/*%< + * Convert a nsec3param rdata to a private rdata. + * + * 'buf' should be at least src->length + 1 in size. + */ + +isc_result_t +dns_nsec3param_deletechains(dns_db_t *db, dns_dbversion_t *ver, + dns_zone_t *zone, dns_diff_t *diff); + +/*%< + * Mark NSEC3PARAM for deletion. + */ + + ISC_LANG_ENDDECLS #endif /* DNS_NSEC3_H */ diff --git a/lib/dns/include/dns/peer.h b/lib/dns/include/dns/peer.h index 1f8a42e..a1a3e34 100644 --- a/lib/dns/include/dns/peer.h +++ b/lib/dns/include/dns/peer.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: peer.h,v 1.33.118.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: peer.h,v 1.35 2009-01-17 23:47:43 tbox Exp $ */ #ifndef DNS_PEER_H #define DNS_PEER_H 1 diff --git a/lib/dns/include/dns/private.h b/lib/dns/include/dns/private.h new file mode 100644 index 0000000..ffedb5f --- /dev/null +++ b/lib/dns/include/dns/private.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: private.h,v 1.3 2009-10-09 23:48:09 tbox Exp $ */ + +#include +#include + +#include +#include + +#ifndef DNS_PRIVATE_H +#define DNS_PRIVATE_H + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_private_chains(dns_db_t *db, dns_dbversion_t *ver, + dns_rdatatype_t privatetype, + isc_boolean_t *build_nsec, isc_boolean_t *build_nsec3); +/*%< + * Examine the NSEC, NSEC3PARAM and privatetype RRsets at the apex of the + * database to determine which of NSEC or NSEC3 chains we are currently + * maintaining. In normal operations only one of NSEC or NSEC3 is being + * maintained but when we are transitiong between NSEC and NSEC3 we need + * to update both sets of chains. If 'privatetype' is zero then the + * privatetype RRset will not be examined. + * + * Requires: + * \li 'db' is valid. + * \li 'version' is valid or NULL. + * \li 'build_nsec' is a pointer to a isc_boolean_t or NULL. + * \li 'build_nsec3' is a pointer to a isc_boolean_t or NULL. + * + * Returns: + * \li ISC_R_SUCCESS, 'build_nsec' and 'build_nsec3' will be valid. + * \li other on error + */ + +ISC_LANG_ENDDECLS + +#endif diff --git a/lib/dns/include/dns/rbt.h b/lib/dns/include/dns/rbt.h index 72ef2f1..6149e8d 100644 --- a/lib/dns/include/dns/rbt.h +++ b/lib/dns/include/dns/rbt.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbt.h,v 1.71.48.3 2009-10-20 05:06:04 marka Exp $ */ +/* $Id: rbt.h,v 1.77 2009-11-04 01:18:19 marka Exp $ */ #ifndef DNS_RBT_H #define DNS_RBT_H 1 @@ -70,6 +70,12 @@ ISC_LANG_BEGINDECLS * multiple dns_rbtnode structures will not work. */ typedef struct dns_rbtnode dns_rbtnode_t; +enum { + DNS_RBT_NSEC_NORMAL=0, /* in main tree */ + DNS_RBT_NSEC_HAS_NSEC=1, /* also has node in nsec tree */ + DNS_RBT_NSEC_NSEC=2, /* in nsec tree */ + DNS_RBT_NSEC_NSEC3=3 /* in nsec3 tree */ +}; struct dns_rbtnode { #if DNS_RBT_USEMAGIC unsigned int magic; @@ -94,10 +100,7 @@ struct dns_rbtnode { * The following bitfields add up to a total bitwidth of 32. * The range of values necessary for each item is indicated, * but in the case of "attributes" the field is wider to accommodate - * possible future expansion. "offsetlen" could be one bit - * narrower by always adjusting its value by 1 to find the real - * offsetlen, but doing so does not gain anything (except perhaps - * another bit for "attributes", which doesn't yet need any more). + * possible future expansion. * * In each case below the "range" indicated is what's _necessary_ for * the bitfield to hold, not what it actually _can_ hold. @@ -105,8 +108,8 @@ struct dns_rbtnode { unsigned int is_root : 1; /*%< range is 0..1 */ unsigned int color : 1; /*%< range is 0..1 */ unsigned int find_callback : 1; /*%< range is 0..1 */ - unsigned int attributes : 4; /*%< range is 0..2 */ - unsigned int nsec3 : 1; /*%< range is 0..1 */ + unsigned int attributes : 3; /*%< range is 0..2 */ + unsigned int nsec : 2; /*%< range is 0..3 */ unsigned int namelen : 8; /*%< range is 1..255 */ unsigned int offsetlen : 8; /*%< range is 1..128 */ unsigned int oldnamelen : 8; /*%< range is 1..255 */ @@ -909,7 +912,7 @@ dns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name); } while (0) #else /* DNS_RBT_USEISCREFCOUNT */ #define dns_rbtnode_refinit(node, n) ((node)->references = (n)) -#define dns_rbtnode_refdestroy(node) (REQUIRE((node)->references == 0)) +#define dns_rbtnode_refdestroy(node) REQUIRE((node)->references == 0) #define dns_rbtnode_refcurrent(node) ((node)->references) #define dns_rbtnode_refincrement0(node, refs) \ do { \ diff --git a/lib/dns/include/dns/rdata.h b/lib/dns/include/dns/rdata.h index 1674b0c..b70a353 100644 --- a/lib/dns/include/dns/rdata.h +++ b/lib/dns/include/dns/rdata.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdata.h,v 1.70.120.3 2009-02-16 00:29:27 marka Exp $ */ +/* $Id: rdata.h,v 1.77 2009-12-04 21:09:33 marka Exp $ */ #ifndef DNS_RDATA_H #define DNS_RDATA_H 1 @@ -95,6 +95,7 @@ #include #include +#include ISC_LANG_BEGINDECLS @@ -124,9 +125,27 @@ struct dns_rdata { #define DNS_RDATA_INIT { NULL, 0, 0, 0, 0, {(void*)(-1), (void *)(-1)}} +#define DNS_RDATA_CHECKINITIALIZED +#ifdef DNS_RDATA_CHECKINITIALIZED +#define DNS_RDATA_INITIALIZED(rdata) \ + ((rdata)->data == NULL && (rdata)->length == 0 && \ + (rdata)->rdclass == 0 && (rdata)->type == 0 && (rdata)->flags == 0 && \ + !ISC_LINK_LINKED((rdata), link)) +#else +#ifdef ISC_LIST_CHECKINIT +#define DNS_RDATA_INITIALIZED(rdata) \ + (!ISC_LINK_LINKED((rdata), link)) +#else +#define DNS_RDATA_INITIALIZED(rdata) ISC_TRUE +#endif +#endif + #define DNS_RDATA_UPDATE 0x0001 /*%< update pseudo record. */ #define DNS_RDATA_OFFLINE 0x0002 /*%< RRSIG has a offline key. */ +#define DNS_RDATA_VALIDFLAGS(rdata) \ + (((rdata)->flags & ~(DNS_RDATA_UPDATE|DNS_RDATA_OFFLINE)) == 0) + /* * Flags affecting rdata formatting style. Flags 0xFFFF0000 * are used by masterfile-level formatting and defined elsewhere. @@ -201,6 +220,25 @@ dns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2); *\li > 0 'rdata1' is greater than 'rdata2' */ +int +dns_rdata_casecompare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2); +/*%< + * dns_rdata_casecompare() is similar to dns_rdata_compare() but also + * compares domain names case insensitively in known rdata types that + * are treated as opaque data by dns_rdata_compare(). + * + * Requires: + * + *\li 'rdata1' is a valid, non-empty rdata + * + *\li 'rdata2' is a valid, non-empty rdata + * + * Returns: + *\li < 0 'rdata1' is less than 'rdata2' + *\li 0 'rdata1' is equal to 'rdata2' + *\li > 0 'rdata1' is greater than 'rdata2' + */ + /*** *** Conversions ***/ @@ -698,6 +736,21 @@ dns_rdata_checknames(dns_rdata_t *rdata, dns_name_t *owner, dns_name_t *bad); * 'bad' to be NULL or valid. */ +void +dns_rdata_exists(dns_rdata_t *rdata, dns_rdatatype_t type); + +void +dns_rdata_notexist(dns_rdata_t *rdata, dns_rdatatype_t type); + +void +dns_rdata_deleterrset(dns_rdata_t *rdata, dns_rdatatype_t type); + +void +dns_rdata_makedelete(dns_rdata_t *rdata); + +const char * +dns_rdata_updateop(dns_rdata_t *rdata, dns_section_t section); + ISC_LANG_ENDDECLS #endif /* DNS_RDATA_H */ diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index a8c3e9c..7f50c12 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdataset.h,v 1.65.50.4.6.3 2011-06-21 20:13:23 each Exp $ */ +/* $Id: rdataset.h,v 1.69.270.3 2011-06-21 20:15:54 each Exp $ */ #ifndef DNS_RDATASET_H #define DNS_RDATASET_H 1 diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h index 8808c0a..f2db1031b 100644 --- a/lib/dns/include/dns/request.h +++ b/lib/dns/include/dns/request.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: request.h,v 1.27.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: request.h,v 1.31 2010-03-04 23:50:34 tbox Exp $ */ #ifndef DNS_REQUEST_H #define DNS_REQUEST_H 1 @@ -47,6 +47,7 @@ #include #define DNS_REQUESTOPT_TCP 0x00000001U +#define DNS_REQUESTOPT_CASE 0x00000002U typedef struct dns_requestevent { ISC_EVENT_COMMON(struct dns_requestevent); @@ -175,6 +176,9 @@ dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message, * #DNS_REQUESTOPT_TCP option is set, TCP will be used. The request * will timeout after 'timeout' seconds. * + *\li If the #DNS_REQUESTOPT_CASE option is set, use case sensitive + * compression. + * *\li When the request completes, successfully, due to a timeout, or * because it was canceled, a completion event will be sent to 'task'. * @@ -227,6 +231,9 @@ dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message, * will timeout after 'timeout' seconds. UDP requests will be resent * at 'udptimeout' intervals if non-zero or 'udpretries' is non-zero. * + *\li If the #DNS_REQUESTOPT_CASE option is set, use case sensitive + * compression. + * *\li When the request completes, successfully, due to a timeout, or * because it was canceled, a completion event will be sent to 'task'. * diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h index c9034bf..2db1770 100644 --- a/lib/dns/include/dns/resolver.h +++ b/lib/dns/include/dns/resolver.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.h,v 1.60.56.5 2010-02-25 10:56:41 tbox Exp $ */ +/* $Id: resolver.h,v 1.67.86.1.2.1 2011-06-02 23:47:36 tbox Exp $ */ #ifndef DNS_RESOLVER_H #define DNS_RESOLVER_H 1 @@ -81,6 +81,7 @@ typedef struct dns_fetchevent { dns_fixedname_t foundname; isc_sockaddr_t * client; dns_messageid_t id; + isc_result_t vresult; } dns_fetchevent_t; /* @@ -179,7 +180,7 @@ dns_resolver_freeze(dns_resolver_t *res); * * Requires: * - *\li 'res' is a valid, unfrozen resolver. + *\li 'res' is a valid resolver. * * Ensures: * @@ -491,6 +492,27 @@ dns_resolver_setmustbesecure(dns_resolver_t *resolver, dns_name_t *name, isc_boolean_t dns_resolver_getmustbesecure(dns_resolver_t *resolver, dns_name_t *name); + +void +dns_resolver_settimeout(dns_resolver_t *resolver, unsigned int seconds); +/*%< + * Set the length of time the resolver will work on a query, in seconds. + * + * If timeout is 0, the default timeout will be applied. + * + * Requires: + * \li resolver to be valid. + */ + +unsigned int +dns_resolver_gettimeout(dns_resolver_t *resolver); +/*%< + * Get the current length of time the resolver will work on a query, in seconds. + * + * Requires: + * \li resolver to be valid. + */ + void dns_resolver_setclientsperquery(dns_resolver_t *resolver, isc_uint32_t min, isc_uint32_t max); diff --git a/lib/dns/include/dns/result.h b/lib/dns/include/dns/result.h index 74b84d6..adc1215 100644 --- a/lib/dns/include/dns/result.h +++ b/lib/dns/include/dns/result.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: result.h,v 1.116.48.2 2010-02-25 10:56:41 tbox Exp $ */ +/* $Id: result.h,v 1.122 2011-01-11 23:47:13 tbox Exp $ */ #ifndef DNS_RESULT_H #define DNS_RESULT_H 1 @@ -148,10 +148,11 @@ #define DNS_R_MXISADDRESS (ISC_RESULTCLASS_DNS + 102) #define DNS_R_DUPLICATE (ISC_RESULTCLASS_DNS + 103) #define DNS_R_INVALIDNSEC3 (ISC_RESULTCLASS_DNS + 104) -#define DNS_R_NOTMASTER (ISC_RESULTCLASS_DNS + 105) +#define DNS_R_NOTMASTER (ISC_RESULTCLASS_DNS + 105) #define DNS_R_BROKENCHAIN (ISC_RESULTCLASS_DNS + 106) +#define DNS_R_EXPIRED (ISC_RESULTCLASS_DNS + 107) -#define DNS_R_NRESULTS 107 /*%< Number of results */ +#define DNS_R_NRESULTS 108 /*%< Number of results */ /* * DNS wire format rcodes. diff --git a/lib/dns/include/dns/rpz.h b/lib/dns/include/dns/rpz.h new file mode 100644 index 0000000..404f517 --- /dev/null +++ b/lib/dns/include/dns/rpz.h @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: rpz.h,v 1.3 2011-01-13 04:59:26 tbox Exp $ */ + +#ifndef DNS_RPZ_H +#define DNS_RPZ_H 1 + +#include + +#include +#include +#include + +ISC_LANG_BEGINDECLS + +#define DNS_RPZ_IP_ZONE "rpz-ip" +#define DNS_RPZ_NSIP_ZONE "rpz-nsip" +#define DNS_RPZ_NSDNAME_ZONE "rpz-nsdname" + +typedef isc_uint8_t dns_rpz_cidr_bits_t; + +typedef enum { + DNS_RPZ_TYPE_BAD, + DNS_RPZ_TYPE_QNAME, + DNS_RPZ_TYPE_IP, + DNS_RPZ_TYPE_NSIP, + DNS_RPZ_TYPE_NSDNAME +} dns_rpz_type_t; + +/* + * Require DNS_RPZ_POLICY_NO_OP < DNS_RPZ_POLICY_NXDOMAIN < + * DNS_RPZ_POLICY_NODATA < DNS_RPZ_POLICY_CNAME. + */ +typedef enum { + DNS_RPZ_POLICY_GIVEN = 0, /* 'given': what something else says */ + DNS_RPZ_POLICY_NO_OP = 1, /* 'no-op': do not rewrite */ + DNS_RPZ_POLICY_NXDOMAIN = 2, /* 'nxdomain': answer with NXDOMAIN */ + DNS_RPZ_POLICY_NODATA = 3, /* 'nodata': answer with ANCOUNT=0 */ + DNS_RPZ_POLICY_CNAME = 4, /* 'cname x': answer with x's rrsets */ + DNS_RPZ_POLICY_RECORD = 5, + DNS_RPZ_POLICY_MISS, + DNS_RPZ_POLICY_ERROR +} dns_rpz_policy_t; + +/* + * Specify a response policy zone. + */ +typedef struct dns_rpz_zone dns_rpz_zone_t; + +struct dns_rpz_zone { + ISC_LINK(dns_rpz_zone_t) link; + int num; + dns_name_t origin; /* Policy zone name */ + dns_name_t nsdname; /* RPZ_NSDNAME_ZONE.origin */ + dns_rpz_policy_t policy; /* RPZ_POLICY_GIVEN or override */ + dns_name_t cname; /* override name for + RPZ_POLICY_CNAME */ +}; + +/* + * Radix trees for response policy IP addresses. + */ +typedef struct dns_rpz_cidr dns_rpz_cidr_t; + +/* + * context for finding the best policy + */ +typedef struct { + unsigned int state; +# define DNS_RPZ_REWRITTEN 0x0001 +# define DNS_RPZ_DONE_QNAME 0x0002 +# define DNS_RPZ_DONE_A 0x0004 +# define DNS_RPZ_RECURSING 0x0008 +# define DNS_RPZ_HAVE_IP 0x0010 +# define DNS_RPZ_HAVE_NSIPv4 0x0020 +# define DNS_RPZ_HAVE_NSIPv6 0x0040 +# define DNS_RPZ_HAD_NSDNAME 0x0080 + /* + * Best match so far. + */ + struct { + dns_rpz_type_t type; + dns_rpz_zone_t *rpz; + dns_rpz_cidr_bits_t prefix; + dns_rpz_policy_t policy; + dns_ttl_t ttl; + isc_result_t result; + dns_zone_t *zone; + dns_db_t *db; + dns_dbnode_t *node; + dns_rdataset_t *rdataset; + } m; + /* + * State for chasing NS names and addresses including recursion. + */ + struct { + unsigned int label; + dns_db_t *db; + dns_rdataset_t *ns_rdataset; + dns_rdatatype_t r_type; + isc_result_t r_result; + dns_rdataset_t *r_rdataset; + } ns; + /* + * State of real query while recursing for NSIP or NSDNAME. + */ + struct { + isc_result_t result; + isc_boolean_t is_zone; + isc_boolean_t authoritative; + dns_zone_t *zone; + dns_db_t *db; + dns_dbnode_t *node; + dns_rdataset_t *rdataset; + dns_rdataset_t *sigrdataset; + dns_rdatatype_t qtype; + } q; + dns_name_t *qname; + dns_name_t *r_name; + dns_name_t *fname; + dns_fixedname_t _qnamef; + dns_fixedname_t _r_namef; + dns_fixedname_t _fnamef; +} dns_rpz_st_t; + +#define DNS_RPZ_TTL_DEFAULT 5 + +/* + * So various response policy zone messages can be turned up or down. + */ +#define DNS_RPZ_ERROR_LEVEL ISC_LOG_WARNING +#define DNS_RPZ_INFO_LEVEL ISC_LOG_INFO +#define DNS_RPZ_DEBUG_LEVEL1 ISC_LOG_DEBUG(1) +#define DNS_RPZ_DEBUG_LEVEL2 ISC_LOG_DEBUG(2) + +const char * +dns_rpz_type2str(dns_rpz_type_t type); + +dns_rpz_policy_t +dns_rpz_str2policy(const char *str); + +void +dns_rpz_set_need(isc_boolean_t need); + +isc_boolean_t +dns_rpz_needed(void); + +void +dns_rpz_cidr_free(dns_rpz_cidr_t **cidr); + +void +dns_rpz_view_destroy(dns_view_t *view); + +isc_result_t +dns_rpz_new_cidr(isc_mem_t *mctx, dns_name_t *origin, + dns_rpz_cidr_t **rbtdb_cidr); +void +dns_rpz_enabled(dns_rpz_cidr_t *cidr, dns_rpz_st_t *st); + +void +dns_rpz_cidr_deleteip(dns_rpz_cidr_t *cidr, dns_name_t *name); + +void +dns_rpz_cidr_addip(dns_rpz_cidr_t *cidr, dns_name_t *name); + +isc_result_t +dns_rpz_cidr_find(dns_rpz_cidr_t *cidr, const isc_netaddr_t *netaddr, + dns_rpz_type_t type, dns_name_t *canon_name, + dns_name_t *search_name, dns_rpz_cidr_bits_t *prefix); + +dns_rpz_policy_t +dns_rpz_decode_cname(dns_rdataset_t *, dns_name_t *selfname); + +#endif /* DNS_RPZ_H */ + diff --git a/lib/dns/include/dns/rriterator.h b/lib/dns/include/dns/rriterator.h new file mode 100644 index 0000000..0087349 --- /dev/null +++ b/lib/dns/include/dns/rriterator.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: rriterator.h,v 1.2 2009-06-30 02:52:32 each Exp $ */ + +#ifndef DNS_RRITERATOR_H +#define DNS_RRITERATOR_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file dns/rriterator.h + * \brief + * Functions for "walking" a zone database, visiting each RR or RRset in turn. + */ + +/***** + ***** Imports + *****/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +ISC_LANG_BEGINDECLS + +/***** + ***** Types + *****/ + +/*% + * A dns_rriterator_t is an iterator that iterates over an entire database, + * returning one RR at a time, in some arbitrary order. + */ + +typedef struct dns_rriterator { + unsigned int magic; + isc_result_t result; + dns_db_t *db; + dns_dbiterator_t *dbit; + dns_dbversion_t *ver; + isc_stdtime_t now; + dns_dbnode_t *node; + dns_fixedname_t fixedname; + dns_rdatasetiter_t *rdatasetit; + dns_rdataset_t rdataset; + dns_rdata_t rdata; +} dns_rriterator_t; + +#define RRITERATOR_MAGIC ISC_MAGIC('R', 'R', 'I', 't') +#define VALID_RRITERATOR(m) ISC_MAGIC_VALID(m, RRITERATOR_MAGIC) + +isc_result_t +dns_rriterator_init(dns_rriterator_t *it, dns_db_t *db, + dns_dbversion_t *ver, isc_stdtime_t now); + +isc_result_t +dns_rriterator_first(dns_rriterator_t *it); + +isc_result_t +dns_rriterator_nextrrset(dns_rriterator_t *it); + +isc_result_t +dns_rriterator_next(dns_rriterator_t *it); + +void +dns_rriterator_current(dns_rriterator_t *it, dns_name_t **name, + isc_uint32_t *ttl, dns_rdataset_t **rdataset, + dns_rdata_t **rdata); + +void +dns_rriterator_pause(dns_rriterator_t *it); + +void +dns_rriterator_destroy(dns_rriterator_t *it); + +ISC_LANG_ENDDECLS + +#endif /* DNS_RRITERATOR_H */ diff --git a/lib/dns/include/dns/sdb.h b/lib/dns/include/dns/sdb.h index 18995ed..5744837 100644 --- a/lib/dns/include/dns/sdb.h +++ b/lib/dns/include/dns/sdb.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sdb.h,v 1.21.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: sdb.h,v 1.23 2009-01-17 23:47:43 tbox Exp $ */ #ifndef DNS_SDB_H #define DNS_SDB_H 1 diff --git a/lib/dns/include/dns/sdlz.h b/lib/dns/include/dns/sdlz.h index 9d2a0ed..b917cc0 100644 --- a/lib/dns/include/dns/sdlz.h +++ b/lib/dns/include/dns/sdlz.h @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2005-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2005-2007, 2009-2011 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -50,7 +50,7 @@ * USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sdlz.h,v 1.7.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: sdlz.h,v 1.14 2011-01-13 08:50:29 tbox Exp $ */ /*! \file dns/sdlz.h */ @@ -74,11 +74,10 @@ typedef struct dns_sdlzlookup dns_sdlzlookup_t; /* A simple DLZ database traversal in progress. */ typedef struct dns_sdlzallnodes dns_sdlzallnodes_t; - -typedef isc_result_t -(*dns_sdlzallnodesfunc_t)(const char *zone, void *driverarg, void *dbdata, - dns_sdlzallnodes_t *allnodes); - +typedef isc_result_t (*dns_sdlzallnodesfunc_t)(const char *zone, + void *driverarg, + void *dbdata, + dns_sdlzallnodes_t *allnodes); /*%< * Method prototype. Drivers implementing the SDLZ interface may * supply an all nodes method. This method is called when the DNS @@ -92,9 +91,9 @@ typedef isc_result_t * does not have to implement an all nodes method. */ -typedef isc_result_t -(*dns_sdlzallowzonexfr_t)(void *driverarg, void *dbdata, const char *name, - const char *client); +typedef isc_result_t (*dns_sdlzallowzonexfr_t)(void *driverarg, + void *dbdata, const char *name, + const char *client); /*%< * Method prototype. Drivers implementing the SDLZ interface may @@ -117,9 +116,9 @@ typedef isc_result_t * error. */ -typedef isc_result_t -(*dns_sdlzauthorityfunc_t)(const char *zone, void *driverarg, void *dbdata, - dns_sdlzlookup_t *lookup); +typedef isc_result_t (*dns_sdlzauthorityfunc_t)(const char *zone, + void *driverarg, void *dbdata, + dns_sdlzlookup_t *lookup); /*%< * Method prototype. Drivers implementing the SDLZ interface may @@ -131,9 +130,9 @@ typedef isc_result_t * method. */ -typedef isc_result_t -(*dns_sdlzcreate_t)(const char *dlzname, unsigned int argc, char *argv[], - void *driverarg, void **dbdata); +typedef isc_result_t (*dns_sdlzcreate_t)(const char *dlzname, + unsigned int argc, char *argv[], + void *driverarg, void **dbdata); /*%< * Method prototype. Drivers implementing the SDLZ interface may @@ -142,8 +141,7 @@ typedef isc_result_t * does not have to implement a create method. */ -typedef void -(*dns_sdlzdestroy_t)(void *driverarg, void *dbdata); +typedef void (*dns_sdlzdestroy_t)(void *driverarg, void *dbdata); /*%< * Method prototype. Drivers implementing the SDLZ interface may @@ -198,6 +196,87 @@ typedef isc_result_t * lookup method. */ +typedef isc_result_t (*dns_sdlznewversion_t)(const char *zone, + void *driverarg, void *dbdata, + void **versionp); +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply a newversion method. This method is called to start a + * write transaction on a zone and should only be implemented by + * writeable backends. + * When implemented, the driver should create a new transaction, and + * fill *versionp with a pointer to the transaction state. The + * closeversion function will be called to close the transaction. + */ + +typedef void (*dns_sdlzcloseversion_t)(const char *zone, isc_boolean_t commit, + void *driverarg, void *dbdata, + void **versionp); +/*%< + * Method prototype. Drivers implementing the SDLZ interface must + * supply a closeversion method if they supply a newversion method. + * When implemented, the driver should close the given transaction, + * committing changes if 'commit' is ISC_TRUE. If 'commit' is not true + * then all changes should be discarded and the database rolled back. + * If the call is successful then *versionp should be set to NULL + */ + +typedef isc_result_t (*dns_sdlzconfigure_t)(dns_view_t *view, void *driverarg, + void *dbdata); +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply a configure method. When supplied, it will be called + * immediately after the create method to give the driver a chance + * to configure writeable zones + */ + + +typedef isc_boolean_t (*dns_sdlzssumatch_t)(const char *signer, + const char *name, + const char *tcpaddr, + const char *type, + const char *key, + isc_uint32_t keydatalen, + unsigned char *keydata, + void *driverarg, + void *dbdata); + +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply a ssumatch method. If supplied, then ssumatch will be + * called to authorize any zone updates. The driver should return + * ISC_TRUE to allow the update, and ISC_FALSE to deny it. For a DLZ + * controlled zone, this is the only access control on updates. + */ + + +typedef isc_result_t (*dns_sdlzmodrdataset_t)(const char *name, + const char *rdatastr, + void *driverarg, void *dbdata, + void *version); +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply addrdataset and subtractrdataset methods. If supplied, then these + * will be called when rdatasets are added/subtracted during + * updates. The version parameter comes from a call to the sdlz + * newversion() method from the driver. The rdataset parameter is a + * linearise string representation of the rdataset change. The format + * is the same as used by dig when displaying records. The fields are + * tab delimited. + */ + +typedef isc_result_t (*dns_sdlzdelrdataset_t)(const char *name, + const char *type, + void *driverarg, void *dbdata, + void *version); +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply a delrdataset method. If supplied, then this + * function will be called when rdatasets are deleted during + * updates. The call should remove all rdatasets of the given type for + * the specified name. + */ + typedef struct dns_sdlzmethods { dns_sdlzcreate_t create; dns_sdlzdestroy_t destroy; @@ -206,6 +285,13 @@ typedef struct dns_sdlzmethods { dns_sdlzauthorityfunc_t authority; dns_sdlzallnodesfunc_t allnodes; dns_sdlzallowzonexfr_t allowzonexfr; + dns_sdlznewversion_t newversion; + dns_sdlzcloseversion_t closeversion; + dns_sdlzconfigure_t configure; + dns_sdlzssumatch_t ssumatch; + dns_sdlzmodrdataset_t addrdataset; + dns_sdlzmodrdataset_t subtractrdataset; + dns_sdlzdelrdataset_t delrdataset; } dns_sdlzmethods_t; isc_result_t @@ -261,6 +347,14 @@ dns_sdlz_putsoa(dns_sdlzlookup_t *lookup, const char *mname, const char *rname, */ +isc_result_t +dns_sdlz_setdb(dns_dlzdb_t *dlzdatabase, dns_rdataclass_t rdclass, + dns_name_t *name, dns_db_t **dbp); +/*%< + * Create the database pointers for a writeable SDLZ zone + */ + + ISC_LANG_ENDDECLS #endif /* SDLZ_H */ diff --git a/lib/dns/include/dns/secalg.h b/lib/dns/include/dns/secalg.h index 0eb0333..49613d5 100644 --- a/lib/dns/include/dns/secalg.h +++ b/lib/dns/include/dns/secalg.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: secalg.h,v 1.19 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: secalg.h,v 1.21 2009-10-12 23:48:02 tbox Exp $ */ #ifndef DNS_SECALG_H #define DNS_SECALG_H 1 @@ -66,6 +66,13 @@ dns_secalg_totext(dns_secalg_t secalg, isc_buffer_t *target); *\li ISC_R_NOSPACE target buffer is too small */ +#define DNS_SECALG_FORMATSIZE 20 +void +dns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size); +/*%< + * Wrapper for dns_secalg_totext(), writing text into 'cp' + */ + ISC_LANG_ENDDECLS #endif /* DNS_SECALG_H */ diff --git a/lib/dns/include/dns/soa.h b/lib/dns/include/dns/soa.h index c1ad706..6ebf61d 100644 --- a/lib/dns/include/dns/soa.h +++ b/lib/dns/include/dns/soa.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: soa.h,v 1.9 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: soa.h,v 1.12 2009-09-10 01:47:09 each Exp $ */ #ifndef DNS_SOA_H #define DNS_SOA_H 1 @@ -40,6 +40,28 @@ ISC_LANG_BEGINDECLS +#define DNS_SOA_BUFFERSIZE ((2 * DNS_NAME_MAXWIRE) + (4 * 5)) + +isc_result_t +dns_soa_buildrdata(dns_name_t *origin, dns_name_t *contact, + dns_rdataclass_t rdclass, + isc_uint32_t serial, isc_uint32_t refresh, + isc_uint32_t retry, isc_uint32_t expire, + isc_uint32_t minimum, unsigned char *buffer, + dns_rdata_t *rdata); +/*%< + * Build the rdata of an SOA record. + * + * Requires: + *\li buffer Points to a temporary buffer of at least + * DNS_SOA_BUFFERSIZE bytes. + *\li rdata Points to an initialized dns_rdata_t. + * + * Ensures: + * \li *rdata Contains a valid SOA rdata. The 'data' member + * refers to 'buffer'. + */ + isc_uint32_t dns_soa_getserial(dns_rdata_t *rdata); isc_uint32_t diff --git a/lib/dns/include/dns/ssu.h b/lib/dns/include/dns/ssu.h index 686928b..5d6c178 100644 --- a/lib/dns/include/dns/ssu.h +++ b/lib/dns/include/dns/ssu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008, 2010, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ssu.h,v 1.24 2008-01-18 23:46:58 tbox Exp $ */ +/* $Id: ssu.h,v 1.28 2011-01-06 23:47:00 tbox Exp $ */ #ifndef DNS_SSU_H #define DNS_SSU_H 1 @@ -25,6 +25,7 @@ #include #include +#include ISC_LANG_BEGINDECLS @@ -40,7 +41,9 @@ ISC_LANG_BEGINDECLS #define DNS_SSUMATCHTYPE_SUBDOMAINKRB5 9 #define DNS_SSUMATCHTYPE_TCPSELF 10 #define DNS_SSUMATCHTYPE_6TO4SELF 11 -#define DNS_SSUMATCHTYPE_MAX 11 /* max value */ +#define DNS_SSUMATCHTYPE_EXTERNAL 12 +#define DNS_SSUMATCHTYPE_DLZ 13 +#define DNS_SSUMATCHTYPE_MAX 12 /* max value */ isc_result_t dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **table); @@ -57,6 +60,16 @@ dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **table); *\li ISC_R_NOMEMORY */ +isc_result_t +dns_ssutable_createdlz(isc_mem_t *mctx, dns_ssutable_t **tablep, + dns_dlzdb_t *dlzdatabase); +/*%< + * Create an SSU table that contains a dlzdatabase pointer, and a + * single rule with matchtype DNS_SSUMATCHTYPE_DLZ. This type of SSU + * table is used by writeable DLZ drivers to offload authorization for + * updates to the driver. + */ + void dns_ssutable_attach(dns_ssutable_t *source, dns_ssutable_t **targetp); /*%< @@ -120,7 +133,7 @@ dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant, isc_boolean_t dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer, dns_name_t *name, isc_netaddr_t *tcpaddr, - dns_rdatatype_t type); + dns_rdatatype_t type, const dst_key_t *key); /*%< * Checks that the attempted update of (name, type) is allowed according * to the rules specified in the simple-secure-update rule table. If @@ -184,6 +197,16 @@ isc_result_t dns_ssutable_nextrule(dns_ssurule_t *rule, *\li #ISC_R_NOMORE */ + +/*%< + * Check a policy rule via an external application + */ +isc_boolean_t +dns_ssu_external_match(dns_name_t *identity, dns_name_t *signer, + dns_name_t *name, isc_netaddr_t *tcpaddr, + dns_rdatatype_t type, const dst_key_t *key, + isc_mem_t *mctx); + ISC_LANG_ENDDECLS #endif /* DNS_SSU_H */ diff --git a/lib/dns/include/dns/stats.h b/lib/dns/include/dns/stats.h index 853c1e9..c19b0c7 100644 --- a/lib/dns/include/dns/stats.h +++ b/lib/dns/include/dns/stats.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: stats.h,v 1.18.56.2 2009-01-29 23:47:44 tbox Exp $ */ +/* $Id: stats.h,v 1.20 2009-01-27 23:47:54 tbox Exp $ */ #ifndef DNS_STATS_H #define DNS_STATS_H 1 diff --git a/lib/dns/include/dns/tkey.h b/lib/dns/include/dns/tkey.h index cb1fe0e..f9e34f8 100644 --- a/lib/dns/include/dns/tkey.h +++ b/lib/dns/include/dns/tkey.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tkey.h,v 1.26.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: tkey.h,v 1.32 2011-01-08 23:47:01 tbox Exp $ */ #ifndef DNS_TKEY_H #define DNS_TKEY_H 1 @@ -44,6 +44,7 @@ struct dns_tkeyctx { gss_cred_id_t gsscred; isc_mem_t *mctx; isc_entropy_t *ectx; + char *gssapi_keytab; }; isc_result_t @@ -123,7 +124,8 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name, isc_result_t dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname, isc_buffer_t *intoken, isc_uint32_t lifetime, - gss_ctx_id_t *context, isc_boolean_t win2k); + gss_ctx_id_t *context, isc_boolean_t win2k, + isc_mem_t *mctx, char **err_message); /*%< * Builds a query containing a TKEY that will generate a GSSAPI context. * The key is requested to have the specified lifetime (in seconds). @@ -141,6 +143,7 @@ dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname, *\li ISC_R_SUCCESS msg was successfully updated to include the * query to be sent *\li other an error occurred while building the message + *\li *err_message optional error message */ @@ -187,7 +190,7 @@ isc_result_t dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, dns_name_t *gname, gss_ctx_id_t *context, isc_buffer_t *outtoken, dns_tsigkey_t **outkey, - dns_tsig_keyring_t *ring); + dns_tsig_keyring_t *ring, char **err_message); /*%< * XXX */ @@ -211,12 +214,11 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg, * component of the query or response */ - isc_result_t dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, dns_name_t *server, gss_ctx_id_t *context, dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring, - isc_boolean_t win2k); + isc_boolean_t win2k, char **err_message); /* * Client side negotiation of GSS-TSIG. Process the response diff --git a/lib/dns/include/dns/tsec.h b/lib/dns/include/dns/tsec.h new file mode 100644 index 0000000..698634e --- /dev/null +++ b/lib/dns/include/dns/tsec.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: tsec.h,v 1.6 2010-12-09 00:54:34 marka Exp $ */ + +#ifndef DNS_TSEC_H +#define DNS_TSEC_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file + * + * \brief + * The TSEC (Transaction Security) module is an abstraction layer for managing + * DNS transaction mechanisms such as TSIG or SIG(0). A TSEC structure is a + * mechanism-independent object containing key information specific to the + * mechanism, and is expected to be used as an argument to other modules + * that use transaction security in a mechanism-independent manner. + * + * MP: + *\li A TSEC structure is expected to be thread-specific. No inter-thread + * synchronization is ensured in multiple access to a single TSEC + * structure. + * + * Resources: + *\li TBS + * + * Security: + *\li This module does not handle any low-level data directly, and so no + * security issue specific to this module is anticipated. + */ + +#include + +#include + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +/*% + * Transaction security types. + */ +typedef enum { + dns_tsectype_none, + dns_tsectype_tsig, + dns_tsectype_sig0 +} dns_tsectype_t; + +isc_result_t +dns_tsec_create(isc_mem_t *mctx, dns_tsectype_t type, dst_key_t *key, + dns_tsec_t **tsecp); +/*%< + * Create a TSEC structure and stores a type-dependent key structure in it. + * For a TSIG key (type is dns_tsectype_tsig), dns_tsec_create() creates a + * TSIG key structure from '*key' and keeps it in the structure. For other + * types, this function simply retains '*key' in the structure. In either + * case, the ownership of '*key' is transferred to the TSEC module; the caller + * must not modify or destroy it after the call to dns_tsec_create(). + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'type' is a valid value of dns_tsectype_t (see above). + * + *\li 'key' is a valid key. + * + *\li tsecp != NULL && *tsecp == NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +void +dns_tsec_destroy(dns_tsec_t **tsecp); +/*%< + * Destroy the TSEC structure. The stored key is also detached or destroyed. + * + * Requires + * + *\li '*tsecp' is a valid TSEC structure. + * + * Ensures + * + *\li *tsecp == NULL. + * + */ + +dns_tsectype_t +dns_tsec_gettype(dns_tsec_t *tsec); +/*%< + * Return the TSEC type of '*tsec'. + * + * Requires + * + *\li 'tsec' is a valid TSEC structure. + * + */ + +void +dns_tsec_getkey(dns_tsec_t *tsec, void *keyp); +/*%< + * Return the TSEC key of '*tsec' in '*keyp'. + * + * Requires + * + *\li keyp != NULL + * + * Ensures + * + *\li *tsecp points to a valid key structure depending on the TSEC type. + */ + +#endif /* DNS_TSEC_H */ diff --git a/lib/dns/include/dns/tsig.h b/lib/dns/include/dns/tsig.h index 5161fb3..ef9423b 100644 --- a/lib/dns/include/dns/tsig.h +++ b/lib/dns/include/dns/tsig.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tsig.h,v 1.51.332.4 2010-12-09 01:12:55 marka Exp $ */ +/* $Id: tsig.h,v 1.59 2011-01-11 23:47:13 tbox Exp $ */ #ifndef DNS_TSIG_H #define DNS_TSIG_H 1 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -69,6 +70,7 @@ struct dns_tsig_keyring { unsigned int generated; unsigned int maxgenerated; ISC_LIST(dns_tsigkey_t) lru; + unsigned int references; }; struct dns_tsigkey { @@ -253,9 +255,30 @@ dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp); *\li #ISC_R_NOMEMORY */ +isc_result_t +dns_tsigkeyring_add(dns_tsig_keyring_t *ring, dns_name_t *name, + dns_tsigkey_t *tkey); +/*%< + * Place a TSIG key onto a key ring. + * + * Requires: + *\li 'ring', 'name' and 'tkey' are not NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li Any other value indicates failure. + */ + + +void +dns_tsigkeyring_attach(dns_tsig_keyring_t *source, dns_tsig_keyring_t **target); void -dns_tsigkeyring_destroy(dns_tsig_keyring_t **ringp); +dns_tsigkeyring_detach(dns_tsig_keyring_t **ringp); + +isc_result_t +dns_tsigkeyring_dumpanddetach(dns_tsig_keyring_t **ringp, FILE *fp); + /*%< * Destroy a TSIG key ring. * @@ -263,6 +286,9 @@ dns_tsigkeyring_destroy(dns_tsig_keyring_t **ringp); *\li 'ringp' is not NULL */ +void +dns_keyring_restore(dns_tsig_keyring_t *ring, FILE *fp); + ISC_LANG_ENDDECLS #endif /* DNS_TSIG_H */ diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 4e4c195..dc02c86 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.130.50.7 2010-05-14 23:47:50 tbox Exp $ */ +/* $Id: types.h,v 1.143 2010-12-08 02:46:16 marka Exp $ */ #ifndef DNS_TYPES_H #define DNS_TYPES_H 1 @@ -44,6 +44,10 @@ typedef struct dns_adbentry dns_adbentry_t; typedef struct dns_adbfind dns_adbfind_t; typedef ISC_LIST(dns_adbfind_t) dns_adbfindlist_t; typedef struct dns_byaddr dns_byaddr_t; +typedef struct dns_client dns_client_t; +typedef void dns_clientrestrans_t; +typedef void dns_clientreqtrans_t; +typedef void dns_clientupdatetrans_t; typedef struct dns_cache dns_cache_t; typedef isc_uint16_t dns_cert_t; typedef struct dns_compress dns_compress_t; @@ -63,6 +67,10 @@ typedef struct dns_dispatchevent dns_dispatchevent_t; typedef struct dns_dispatchlist dns_dispatchlist_t; typedef struct dns_dispatchmgr dns_dispatchmgr_t; typedef struct dns_dispentry dns_dispentry_t; +typedef struct dns_dns64 dns_dns64_t; +typedef ISC_LIST(dns_dns64_t) dns_dns64list_t; +typedef struct dns_dnsseckey dns_dnsseckey_t; +typedef ISC_LIST(dns_dnsseckey_t) dns_dnsseckeylist_t; typedef struct dns_dumpctx dns_dumpctx_t; typedef struct dns_fetch dns_fetch_t; typedef struct dns_fixedname dns_fixedname_t; @@ -72,6 +80,7 @@ typedef struct dns_iptable dns_iptable_t; typedef isc_uint32_t dns_iterations_t; typedef isc_uint16_t dns_keyflags_t; typedef struct dns_keynode dns_keynode_t; +typedef ISC_LIST(dns_keynode_t) dns_keynodelist_t; typedef struct dns_keytable dns_keytable_t; typedef isc_uint16_t dns_keytag_t; typedef struct dns_loadctx dns_loadctx_t; @@ -111,6 +120,7 @@ typedef struct dns_stats dns_stats_t; typedef isc_uint32_t dns_rdatastatstype_t; typedef struct dns_tkeyctx dns_tkeyctx_t; typedef isc_uint16_t dns_trust_t; +typedef struct dns_tsec dns_tsec_t; typedef struct dns_tsig_keyring dns_tsig_keyring_t; typedef struct dns_tsigkey dns_tsigkey_t; typedef isc_uint32_t dns_ttl_t; @@ -179,6 +189,12 @@ typedef enum { dns_masterformat_raw = 2 } dns_masterformat_t; +typedef enum { + dns_v4_aaaa_ok = 0, + dns_v4_aaaa_filter = 1, + dns_v4_aaaa_break_dnssec = 2 +} dns_v4_aaaa_t; + /* * These are generated by gen.c. */ diff --git a/lib/dns/include/dns/validator.h b/lib/dns/include/dns/validator.h index fb5b834..5fec135 100644 --- a/lib/dns/include/dns/validator.h +++ b/lib/dns/include/dns/validator.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: validator.h,v 1.41.48.5 2010-02-25 10:56:41 tbox Exp $ */ +/* $Id: validator.h,v 1.46 2010-02-25 05:08:01 tbox Exp $ */ #ifndef DNS_VALIDATOR_H #define DNS_VALIDATOR_H 1 diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index ec96d4c..4b24023 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.h,v 1.111.88.6 2010-09-24 08:30:28 tbox Exp $ */ +/* $Id: view.h,v 1.132 2011-01-13 01:59:28 marka Exp $ */ #ifndef DNS_VIEW_H #define DNS_VIEW_H 1 @@ -73,6 +73,8 @@ #include #include +#include +#include #include ISC_LANG_BEGINDECLS @@ -92,8 +94,13 @@ struct dns_view { dns_cache_t * cache; dns_db_t * cachedb; dns_db_t * hints; - dns_keytable_t * secroots; - dns_keytable_t * trustedkeys; + + /* + * security roots. + * internal use only; access via * dns_view_getsecroots() + */ + dns_keytable_t * secroots_priv; + isc_mutex_t lock; isc_boolean_t frozen; isc_task_t * task; @@ -102,6 +109,7 @@ struct dns_view { isc_event_t reqevent; isc_stats_t * resstats; dns_stats_t * resquerystats; + isc_boolean_t cacheshared; /* Configurable data. */ dns_tsig_keyring_t * statickeys; @@ -129,6 +137,10 @@ struct dns_view { dns_acl_t * transferacl; dns_acl_t * updateacl; dns_acl_t * upfwdacl; + dns_acl_t * denyansweracl; + dns_rbt_t * answeracl_exclude; + dns_rbt_t * denyanswernames; + dns_rbt_t * answernames_exclude; isc_boolean_t requestixfr; isc_boolean_t provideixfr; isc_boolean_t requestnsid; @@ -145,6 +157,11 @@ struct dns_view { dns_name_t * dlv; dns_fixedname_t dlv_fixed; isc_uint16_t maxudp; + dns_v4_aaaa_t v4_aaaa; + dns_acl_t * v4_aaaa_acl; + dns_dns64list_t dns64; + unsigned int dns64cnt; + ISC_LIST(dns_rpz_zone_t) rpz_zones; /* * Configurable data for server use only, @@ -162,6 +179,17 @@ struct dns_view { unsigned int attributes; /* Under owner's locking control. */ ISC_LINK(struct dns_view) link; + dns_viewlist_t * viewlist; + + dns_zone_t * managed_keys; + +#ifdef BIND9 + /* File in which to store configuration for newly added zones */ + char * new_zone_file; + + void * new_zone_config; + void (*cfg_destroy)(void **); +#endif }; #define DNS_VIEW_MAGIC ISC_MAGIC('V','i','e','w') @@ -310,8 +338,12 @@ dns_view_createresolver(dns_view_t *view, void dns_view_setcache(dns_view_t *view, dns_cache_t *cache); +void +dns_view_setcache2(dns_view_t *view, dns_cache_t *cache, isc_boolean_t shared); /*%< - * Set the view's cache database. + * Set the view's cache database. If 'shared' is true, this means the cache + * is created by another view and is shared with that view. dns_view_setcache() + * is a backward compatible version equivalent to setcache2(..., ISC_FALSE). * * Requires: * @@ -346,6 +378,8 @@ dns_view_sethints(dns_view_t *view, dns_db_t *hints); void dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring); +void +dns_view_setdynamickeyring(dns_view_t *view, dns_tsig_keyring_t *ring); /*%< * Set the view's static TSIG keys * @@ -362,6 +396,15 @@ dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring); */ void +dns_view_getdynamickeyring(dns_view_t *view, dns_tsig_keyring_t **ringp); +/*%< + * Return the views dynamic keys. + * + * \li 'view' is a valid, unfrozen view. + * \li 'ringp' != NULL && ringp == NULL. + */ + +void dns_view_setdstport(dns_view_t *view, in_port_t dstport); /*%< * Set the view's destination port. This is the port to @@ -398,7 +441,7 @@ dns_view_addzone(dns_view_t *view, dns_zone_t *zone); void dns_view_freeze(dns_view_t *view); /*%< - * Freeze view. + * Freeze view. No changes can be made to view configuration while frozen. * * Requires: * @@ -409,14 +452,44 @@ dns_view_freeze(dns_view_t *view); *\li 'view' is frozen. */ +void +dns_view_thaw(dns_view_t *view); +/*%< + * Thaw view. This allows zones to be added or removed at runtime. This is + * NOT thread-safe; the caller MUST have run isc_task_exclusive() prior to + * thawing the view. + * + * Requires: + * + *\li 'view' is a valid, frozen view. + * + * Ensures: + * + *\li 'view' is no longer frozen. + */ isc_result_t dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints, dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset); +isc_result_t +dns_view_find2(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, + isc_stdtime_t now, unsigned int options, + isc_boolean_t use_hints, isc_boolean_t use_static_stub, + dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset); /*%< * Find an rdataset whose owner name is 'name', and whose type is * 'type'. + * In general, this function first searches view's zone and cache DBs for the + * best match data against 'name'. If nothing found there, and if 'use_hints' + * is ISC_TRUE, the view's hint DB (if configured) is searched. + * If the view is configured with a static-stub zone which gives the longest + * match for 'name' among the zones, however, the cache DB is not consulted + * unless 'use_static_stub' is ISC_FALSE (see below about this argument). + * + * dns_view_find() is a backward compatible version equivalent to + * dns_view_find2() with use_static_stub argument being ISC_FALSE. * * Notes: * @@ -432,6 +505,23 @@ dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, * in the hints database but not the type, the result code will be * #DNS_R_HINTNXRRSET. * + *\li If 'use_static_stub' is ISC_FALSE and the longest match zone for 'name' + * is a static-stub zone, it's ignored and the cache and/or hints will be + * searched. In the majority of the cases this argument should be + * ISC_FALSE. The only known usage of this argument being ISC_TRUE is + * if this search is for a "bailiwick" glue A or AAAA RRset that may + * best match a static-stub zone. Consider the following example: + * this view is configured with a static-stub zone "example.com", + * and an attempt of recursive resolution needs to send a query for the + * zone. In this case it's quite likely that the resolver is trying to + * find A/AAAA RRs for the apex name "example.com". And, to honor the + * static-stub configuration it needs to return the glue RRs in the + * static-stub zone even if that exact RRs coming from the authoritative + * zone has been cached. + * In other general cases, the requested data is better to be + * authoritative, either locally configured or retrieved from an external + * server, and the data in the static-stub zone should better be ignored. + * *\li 'foundname' must meet the requirements of dns_db_find(). * *\li If 'sigrdataset' is not NULL, and there is a SIG rdataset which @@ -728,8 +818,14 @@ dns_view_dumpdbtostream(dns_view_t *view, FILE *fp); isc_result_t dns_view_flushcache(dns_view_t *view); +isc_result_t +dns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly); /*%< - * Flush the view's cache (and ADB). + * Flush the view's cache (and ADB). If 'fixuponly' is true, it only updates + * the internal reference to the cache DB with omitting actual flush operation. + * 'fixuponly' is intended to be used for a view that shares a cache with + * a different view. dns_view_flushcache() is a backward compatible version + * that always sets fixuponly to false. * * Requires: * 'view' is valid. @@ -878,4 +974,105 @@ dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp); *\li 'statsp' != NULL && '*statsp' != NULL */ +isc_boolean_t +dns_view_iscacheshared(dns_view_t *view); +/*%< + * Check if the view shares the cache created by another view. + * + * Requires: + * \li 'view' is valid. + * + * Returns: + *\li #ISC_TRUE if the cache is shared. + *\li #ISC_FALSE otherwise. + */ + +isc_result_t +dns_view_initsecroots(dns_view_t *view, isc_mem_t *mctx); +/*%< + * Initialize security roots for the view. (Note that secroots is + * NULL until this function is called, so any function using + * secroots must check its validity first. One way to do this is + * use dns_view_getsecroots() and check its return value.) + * + * Requires: + * \li 'view' is valid. + * \li 'view->secroots' is NULL. + * + * Returns: + *\li ISC_R_SUCCESS + *\li Any other result indicates failure + */ + +isc_result_t +dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp); +/*%< + * Get the security roots for this view. Returns ISC_R_NOTFOUND if + * the security roots keytable has not been initialized for the view. + * + * '*ktp' is attached on success; the caller is responsible for + * detaching it with dns_keytable_detach(). + * + * Requires: + * \li 'view' is valid. + * \li 'ktp' is not NULL and '*ktp' is NULL. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOTFOUND + */ + +isc_result_t +dns_view_issecuredomain(dns_view_t *view, dns_name_t *name, + isc_boolean_t *secure_domain); +/*%< + * Is 'name' at or beneath a trusted key? Put answer in + * '*secure_domain'. + * + * Requires: + * \li 'view' is valid. + * + * Returns: + *\li ISC_R_SUCCESS + *\li Any other value indicates failure + */ + +void +dns_view_untrust(dns_view_t *view, dns_name_t *keyname, + dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx); +/*%< + * Remove keys that match 'keyname' and 'dnskey' from the views trust + * anchors. + * + * Requires: + * \li 'view' is valid. + * \li 'keyname' is valid. + * \li 'mctx' is valid. + * \li 'dnskey' is valid. + */ + +void +dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx, + void (*cfg_destroy)(void **)); +/*%< + * Set whether or not to allow zones to be created or deleted at runtime. + * + * If 'allow' is ISC_TRUE, determines the filename into which new zone + * configuration will be written. Preserves the configuration context + * (a pointer to which is passed in 'cfgctx') for use when parsing new + * zone configuration. 'cfg_destroy' points to a callback routine to + * destroy the configuration context when the view is destroyed. (This + * roundabout method is used in order to avoid libdns having a dependency + * on libisccfg and libbind9.) + * + * If 'allow' is ISC_FALSE, removes any existing references to + * configuration context and frees any memory. + * + * Requires: + * \li 'view' is valid. + */ + +void +dns_view_restorekeyring(dns_view_t *view); + #endif /* DNS_VIEW_H */ diff --git a/lib/dns/include/dns/xfrin.h b/lib/dns/include/dns/xfrin.h index b957e25..58910d2 100644 --- a/lib/dns/include/dns/xfrin.h +++ b/lib/dns/include/dns/xfrin.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: xfrin.h,v 1.28.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: xfrin.h,v 1.30 2009-01-17 23:47:43 tbox Exp $ */ #ifndef DNS_XFRIN_H #define DNS_XFRIN_H 1 diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 96cb998..67756d9 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.h,v 1.160.50.8 2010-12-14 23:46:09 tbox Exp $ */ +/* $Id: zone.h,v 1.182 2010-12-18 01:56:22 each Exp $ */ #ifndef DNS_ZONE_H #define DNS_ZONE_H 1 @@ -40,7 +40,10 @@ typedef enum { dns_zone_none, dns_zone_master, dns_zone_slave, - dns_zone_stub + dns_zone_stub, + dns_zone_staticstub, + dns_zone_key, + dns_zone_dlz } dns_zonetype_t; #define DNS_ZONEOPT_SERVERS 0x00000001U /*%< perform server checks */ @@ -70,6 +73,10 @@ typedef enum { #define DNS_ZONEOPT_TRYTCPREFRESH 0x01000000U /*%< try tcp refresh on udp failure */ #define DNS_ZONEOPT_NOTIFYTOSOA 0x02000000U /*%< Notify the SOA MNAME */ #define DNS_ZONEOPT_NSEC3TESTZONE 0x04000000U /*%< nsec3-test-zone */ +#define DNS_ZONEOPT_SECURETOINSECURE 0x08000000U /*%< dnssec-secure-to-insecure */ +#define DNS_ZONEOPT_DNSKEYKSKONLY 0x10000000U /*%< dnssec-dnskey-kskonly */ +#define DNS_ZONEOPT_CHECKDUPRR 0x20000000U /*%< check-dup-records */ +#define DNS_ZONEOPT_CHECKDUPRRFAIL 0x40000000U /*%< fatal check-dup-records failures */ #ifndef NOMINUM_PUBLIC /* @@ -78,6 +85,14 @@ typedef enum { #define DNS_ZONEOPT_NOTIFYFORWARD 0x80000000U /* forward notify to master */ #endif /* NOMINUM_PUBLIC */ +/* + * Zone key maintenance options + */ +#define DNS_ZONEKEY_ALLOW 0x00000001U /*%< fetch keys on command */ +#define DNS_ZONEKEY_MAINTAIN 0x00000002U /*%< publish/sign on schedule */ +#define DNS_ZONEKEY_CREATE 0x00000004U /*%< make keys when needed */ +#define DNS_ZONEKEY_FULLSIGN 0x00000008U /*%< roll to new keys immediately */ + #ifndef DNS_ZONE_MINREFRESH #define DNS_ZONE_MINREFRESH 300 /*%< 5 minutes */ #endif @@ -367,6 +382,22 @@ dns_zone_getdb(dns_zone_t *zone, dns_db_t **dbp); *\li DNS_R_NOTLOADED */ +void +dns_zone_setdb(dns_zone_t *zone, dns_db_t *db); +/*%< + * Sets the zone database to 'db'. + * + * This function is expected to be used to configure a zone with a + * database which is not loaded from a file or zone transfer. + * It can be used for a general purpose zone, but right now its use + * is limited to static-stub zones to avoid possible undiscovered + * problems in the general cases. + * + * Require: + *\li 'zone' to be a valid zone of static-stub. + *\li zone doesn't have a database. + */ + isc_result_t dns_zone_setdbtype(dns_zone_t *zone, unsigned int dbargc, const char * const *dbargv); @@ -568,6 +599,25 @@ dns_zone_getoptions(dns_zone_t *zone); */ void +dns_zone_setkeyopt(dns_zone_t *zone, unsigned int option, isc_boolean_t value); +/*%< + * Set key options on ('value' == ISC_TRUE) or off ('value' == + * #ISC_FALSE). + * + * Require: + *\li 'zone' to be a valid zone. + */ + +unsigned int +dns_zone_getkeyopts(dns_zone_t *zone); +/*%< + * Returns the current zone key options. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void dns_zone_setminrefreshtime(dns_zone_t *zone, isc_uint32_t val); /*%< * Set the minimum refresh time. @@ -1747,6 +1797,61 @@ dns_zone_getprivatetype(dns_zone_t *zone); * will not be permanent. */ +void +dns_zone_rekey(dns_zone_t *zone, isc_boolean_t fullsign); +/*%< + * Update the zone's DNSKEY set from the key repository. + * + * If 'fullsign' is true, trigger an immediate full signing of + * the zone with the new key. Otherwise, if there are no keys or + * if the new keys are for algorithms that have already signed the + * zone, then the zone can be re-signed incrementally. + */ + +isc_result_t +dns_zone_nscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, + unsigned int *errors); +/*% + * Check if the name servers for the zone are sane (have address, don't + * refer to CNAMEs/DNAMEs. The number of constiancy errors detected in + * returned in '*errors' + * + * Requires: + * \li 'zone' to be valid. + * \li 'db' to be valid. + * \li 'version' to be valid or NULL. + * \li 'errors' to be non NULL. + * + * Returns: + * ISC_R_SUCCESS if there were no errors examining the zone contents. + */ + +void +dns_zone_setadded(dns_zone_t *zone, isc_boolean_t added); +/*% + * Sets the value of zone->added, which should be ISC_TRUE for + * zones that were originally added by "rndc addzone". + * + * Requires: + * \li 'zone' to be valid. + */ + +isc_boolean_t +dns_zone_getadded(dns_zone_t *zone); +/*% + * Returns ISC_TRUE if the zone was originally added at runtime + * using "rndc addzone". + * + * Requires: + * \li 'zone' to be valid. + */ + +isc_result_t +dns_zone_dlzpostload(dns_zone_t *zone, dns_db_t *db); +/*% + * Load the origin names for a writeable DLZ database. + */ + ISC_LANG_ENDDECLS #endif /* DNS_ZONE_H */ diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index 1a30d2b..3c999f6 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst.h,v 1.12.50.3 2010-12-09 01:12:55 marka Exp $ */ +/* $Id: dst.h,v 1.31 2011-01-11 23:47:14 tbox Exp $ */ #ifndef DST_DST_H #define DST_DST_H 1 @@ -23,8 +23,11 @@ /*! \file dst/dst.h */ #include +#include #include +#include +#include #include @@ -55,6 +58,7 @@ typedef struct dst_context dst_context_t; #define DST_ALG_NSEC3RSASHA1 7 #define DST_ALG_RSASHA256 8 #define DST_ALG_RSASHA512 10 +#define DST_ALG_ECCGOST 12 #define DST_ALG_HMACMD5 157 #define DST_ALG_GSSAPI 160 #define DST_ALG_HMACSHA1 161 /* XXXMPA */ @@ -80,12 +84,55 @@ typedef struct dst_context dst_context_t; #define DST_TYPE_PRIVATE 0x2000000 #define DST_TYPE_PUBLIC 0x4000000 +/* Key timing metadata definitions */ +#define DST_TIME_CREATED 0 +#define DST_TIME_PUBLISH 1 +#define DST_TIME_ACTIVATE 2 +#define DST_TIME_REVOKE 3 +#define DST_TIME_INACTIVE 4 +#define DST_TIME_DELETE 5 +#define DST_TIME_DSPUBLISH 6 +#define DST_MAX_TIMES 6 + +/* Numeric metadata definitions */ +#define DST_NUM_PREDECESSOR 0 +#define DST_NUM_SUCCESSOR 1 +#define DST_NUM_MAXTTL 2 +#define DST_NUM_ROLLPERIOD 3 +#define DST_MAX_NUMERIC 3 + +/* + * Current format version number of the private key parser. + * + * When parsing a key file with the same major number but a higher minor + * number, the key parser will ignore any fields it does not recognize. + * Thus, DST_MINOR_VERSION should be incremented whenever new + * fields are added to the private key file (such as new metadata). + * + * When rewriting these keys, those fields will be dropped, and the + * format version set back to the current one.. + * + * When a key is seen with a higher major number, the key parser will + * reject it as invalid. Thus, DST_MAJOR_VERSION should be incremented + * and DST_MINOR_VERSION set to zero whenever there is a format change + * which is not backward compatible to previous versions of the dst_key + * parser, such as change in the syntax of an existing field, the removal + * of a currently mandatory field, or a new field added which would + * alter the functioning of the key if it were absent. + */ +#define DST_MAJOR_VERSION 1 +#define DST_MINOR_VERSION 3 + /*** *** Functions ***/ isc_result_t dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags); + +isc_result_t +dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx, + const char *engine, unsigned int eflags); /*%< * Initializes the DST subsystem. * @@ -96,6 +143,7 @@ dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags); * Returns: * \li ISC_R_SUCCESS * \li ISC_R_NOMEMORY + * \li DST_R_NOENGINE * * Ensures: * \li DST is properly initialized. @@ -244,13 +292,17 @@ dst_key_fromfile(dns_name_t *name, dns_keytag_t id, unsigned int alg, int type, */ isc_result_t -dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, - dst_key_t **keyp); +dst_key_fromnamedfile(const char *filename, const char *dirname, + int type, isc_mem_t *mctx, dst_key_t **keyp); /*%< * Reads a key from permanent storage. The key can either be a public or * key, and is specified by filename. If a private key is specified, the * public key must also be present. * + * If 'dirname' is not NULL, and 'filename' is a relative path, + * then the file is looked up relative to the given directory. + * If 'filename' is an absolute path, 'dirname' is ignored. + * * Requires: * \li "filename" is not NULL * \li "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union @@ -419,7 +471,7 @@ dst_key_getgssctx(const dst_key_t *key); isc_result_t dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx, - dst_key_t **keyp); + dst_key_t **keyp, isc_region_t *intoken); /*%< * Converts a GSSAPI opaque context id into a DST key. * @@ -450,6 +502,14 @@ dst_key_generate(dns_name_t *name, unsigned int alg, unsigned int flags, unsigned int protocol, dns_rdataclass_t rdclass, isc_mem_t *mctx, dst_key_t **keyp); + +isc_result_t +dst_key_generate2(dns_name_t *name, unsigned int alg, + unsigned int bits, unsigned int param, + unsigned int flags, unsigned int protocol, + dns_rdataclass_t rdclass, + isc_mem_t *mctx, dst_key_t **keyp, + void (*callback)(int)); /*%< * Generate a DST key (or keypair) with the supplied parameters. The * interpretation of the "param" field depends on the algorithm: @@ -482,7 +542,31 @@ dst_key_generate(dns_name_t *name, unsigned int alg, isc_boolean_t dst_key_compare(const dst_key_t *key1, const dst_key_t *key2); /*%< - * Compares two DST keys. + * Compares two DST keys. Returns true if they match, false otherwise. + * + * Keys ARE NOT considered to match if one of them is the revoked version + * of the other. + * + * Requires: + *\li "key1" is a valid key. + *\li "key2" is a valid key. + * + * Returns: + *\li ISC_TRUE + * \li ISC_FALSE + */ + +isc_boolean_t +dst_key_pubcompare(const dst_key_t *key1, const dst_key_t *key2, + isc_boolean_t match_revoked_key); +/*%< + * Compares only the public portions of two DST keys. Returns true + * if they match, false otherwise. This allows us, for example, to + * determine whether a public key found in a zone matches up with a + * key pair found on disk. + * + * If match_revoked_key is TRUE, then keys ARE considered to match if one + * of them is the revoked version of the other. Otherwise, they are not. * * Requires: *\li "key1" is a valid key. @@ -521,10 +605,12 @@ dst_key_attach(dst_key_t *source, dst_key_t **target); void dst_key_free(dst_key_t **keyp); /*%< - * Release all memory associated with the key. + * Decrement the key's reference counter and, when it reaches zero, + * release all memory associated with the key. * * Requires: *\li "keyp" is not NULL and "*keyp" is a valid key. + *\li reference counter greater than zero. * * Ensures: *\li All memory associated with "*keyp" will be freed. @@ -633,7 +719,7 @@ dst_region_computeid(const isc_region_t *source, unsigned int alg); isc_uint16_t dst_key_getbits(const dst_key_t *key); -/* +/*%< * Get the number of digest bits required (0 == MAX). * * Requires: @@ -642,13 +728,150 @@ dst_key_getbits(const dst_key_t *key); void dst_key_setbits(dst_key_t *key, isc_uint16_t bits); -/* +/*%< * Set the number of digest bits required (0 == MAX). * * Requires: * "key" is a valid key. */ +isc_result_t +dst_key_setflags(dst_key_t *key, isc_uint32_t flags); +/* + * Set the key flags, and recompute the key ID. + * + * Requires: + * "key" is a valid key. + */ + +isc_result_t +dst_key_getnum(const dst_key_t *key, int type, isc_uint32_t *valuep); +/*%< + * Get a member of the numeric metadata array and place it in '*valuep'. + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_NUMERIC + * "timep" is not null. + */ + +void +dst_key_setnum(dst_key_t *key, int type, isc_uint32_t value); +/*%< + * Set a member of the numeric metadata array. + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_NUMERIC + */ + +void +dst_key_unsetnum(dst_key_t *key, int type); +/*%< + * Flag a member of the numeric metadata array as "not set". + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_NUMERIC + */ + +isc_result_t +dst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep); +/*%< + * Get a member of the timing metadata array and place it in '*timep'. + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_TIMES + * "timep" is not null. + */ + +void +dst_key_settime(dst_key_t *key, int type, isc_stdtime_t when); +/*%< + * Set a member of the timing metadata array. + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_TIMES + */ + +void +dst_key_unsettime(dst_key_t *key, int type); +/*%< + * Flag a member of the timing metadata array as "not set". + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_TIMES + */ + +isc_result_t +dst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp); +/*%< + * Get the private key format version number. (If the key does not have + * a private key associated with it, the version will be 0.0.) The major + * version number is placed in '*majorp', and the minor version number in + * '*minorp'. + * + * Requires: + * "key" is a valid key. + * "majorp" is not NULL. + * "minorp" is not NULL. + */ + +void +dst_key_setprivateformat(dst_key_t *key, int major, int minor); +/*%< + * Set the private key format version number. + * + * Requires: + * "key" is a valid key. + */ + +#define DST_KEY_FORMATSIZE (DNS_NAME_FORMATSIZE + DNS_SECALG_FORMATSIZE + 7) + +void +dst_key_format(const dst_key_t *key, char *cp, unsigned int size); +/*%< + * Write the uniquely identifying information about the key (name, + * algorithm, key ID) into a string 'cp' of size 'size'. + */ + + +isc_buffer_t * +dst_key_tkeytoken(const dst_key_t *key); +/*%< + * Return the token from the TKEY request, if any. If this key was + * not negotiated via TKEY, return NULL. + */ + + +isc_result_t +dst_key_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length); +/*%< + * Allocate 'buffer' and dump the key into it in base64 format. The buffer + * is not NUL terminated. The length of the buffer is returned in *length. + * + * 'buffer' needs to be freed using isc_mem_put(mctx, buffer, length); + * + * Requires: + * 'buffer' to be non NULL and *buffer to be NULL. + * 'length' to be non NULL and *length to be zero. + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOMEMORY + * ISC_R_NOTIMPLEMENTED + * others. + */ + +isc_result_t +dst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags, + unsigned int protocol, dns_rdataclass_t rdclass, + isc_mem_t *mctx, const char *keystr, dst_key_t **keyp); + + ISC_LANG_ENDDECLS #endif /* DST_DST_H */ diff --git a/lib/dns/include/dst/gssapi.h b/lib/dns/include/dst/gssapi.h index 0a468d3..189e6b5 100644 --- a/lib/dns/include/dst/gssapi.h +++ b/lib/dns/include/dst/gssapi.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: gssapi.h,v 1.9.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: gssapi.h,v 1.16 2011-01-08 23:47:01 tbox Exp $ */ #ifndef DST_GSSAPI_H #define DST_GSSAPI_H 1 @@ -34,8 +34,12 @@ * MSVC does not like macros in #include lines. */ #include +#include #else #include ISC_PLATFORM_GSSAPIHEADER +#ifdef ISC_PLATFORM_GSSAPI_KRB5_HEADER +#include ISC_PLATFORM_GSSAPI_KRB5_HEADER +#endif #endif #ifndef GSS_SPNEGO_MECHANISM #define GSS_SPNEGO_MECHANISM ((void*)0) @@ -90,7 +94,8 @@ dst_gssapi_releasecred(gss_cred_id_t *cred); isc_result_t dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, - isc_buffer_t *outtoken, gss_ctx_id_t *gssctx); + isc_buffer_t *outtoken, gss_ctx_id_t *gssctx, + isc_mem_t *mctx, char **err_message); /* * Initiates a GSS context. * @@ -108,10 +113,12 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, * ISC_R_SUCCESS msg was successfully updated to include the * query to be sent * other an error occurred while building the message + * *err_message optional error message */ isc_result_t dst_gssapi_acceptctx(gss_cred_id_t cred, + const char *gssapi_keytab, isc_region_t *intoken, isc_buffer_t **outtoken, gss_ctx_id_t *context, dns_name_t *principal, isc_mem_t *mctx); diff --git a/lib/dns/iptable.c b/lib/dns/iptable.c index 071f9a6..7c334dd 100644 --- a/lib/dns/iptable.c +++ b/lib/dns/iptable.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: iptable.c,v 1.12.44.3 2009-02-18 23:47:12 tbox Exp $ */ +/* $Id: iptable.c,v 1.15 2009-02-18 23:47:48 tbox Exp $ */ #include diff --git a/lib/dns/journal.c b/lib/dns/journal.c index 520083e..a6d630e 100644 --- a/lib/dns/journal.c +++ b/lib/dns/journal.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: journal.c,v 1.103.48.8 2010-11-17 23:45:45 tbox Exp $ */ +/* $Id: journal.c,v 1.112 2010-11-17 23:47:08 tbox Exp $ */ #include @@ -562,11 +562,9 @@ journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write, if (result == ISC_R_FILENOTFOUND) { if (create) { - isc_log_write(JOURNAL_COMMON_LOGARGS, - ISC_LOG_INFO, + isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_DEBUG(1), "journal file %s does not exist, " - "creating it", - j->filename); + "creating it", j->filename); CHECK(journal_file_create(mctx, filename)); /* * Retry. diff --git a/lib/dns/keydata.c b/lib/dns/keydata.c new file mode 100644 index 0000000..c2f82c8 --- /dev/null +++ b/lib/dns/keydata.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: keydata.c,v 1.3 2009-07-01 23:47:36 tbox Exp $ */ + +/*! \file */ + +#include + + +#include +#include +#include +#include + +#include +#include +#include + +isc_result_t +dns_keydata_todnskey(dns_rdata_keydata_t *keydata, + dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx) +{ + REQUIRE(keydata != NULL && dnskey != NULL); + + dnskey->common.rdtype = dns_rdatatype_dnskey; + dnskey->common.rdclass = keydata->common.rdclass; + dnskey->mctx = mctx; + dnskey->flags = keydata->flags; + dnskey->protocol = keydata->protocol; + dnskey->algorithm = keydata->algorithm; + + dnskey->datalen = keydata->datalen; + + if (mctx == NULL) + dnskey->data = keydata->data; + else { + dnskey->data = isc_mem_allocate(mctx, dnskey->datalen); + if (dnskey->data == NULL) + return (ISC_R_NOMEMORY); + memcpy(dnskey->data, keydata->data, dnskey->datalen); + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_keydata_fromdnskey(dns_rdata_keydata_t *keydata, + dns_rdata_dnskey_t *dnskey, + isc_uint32_t refresh, isc_uint32_t addhd, + isc_uint32_t removehd, isc_mem_t *mctx) +{ + REQUIRE(keydata != NULL && dnskey != NULL); + + keydata->common.rdtype = dns_rdatatype_keydata; + keydata->common.rdclass = dnskey->common.rdclass; + keydata->mctx = mctx; + keydata->refresh = refresh; + keydata->addhd = addhd; + keydata->removehd = removehd; + keydata->flags = dnskey->flags; + keydata->protocol = dnskey->protocol; + keydata->algorithm = dnskey->algorithm; + + keydata->datalen = dnskey->datalen; + if (mctx == NULL) + keydata->data = dnskey->data; + else { + keydata->data = isc_mem_allocate(mctx, keydata->datalen); + if (keydata->data == NULL) + return (ISC_R_NOMEMORY); + memcpy(keydata->data, dnskey->data, keydata->datalen); + } + + return (ISC_R_SUCCESS); +} diff --git a/lib/dns/keytable.c b/lib/dns/keytable.c index 874868d..3edc3d6 100644 --- a/lib/dns/keytable.c +++ b/lib/dns/keytable.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: keytable.c,v 1.34 2007-06-19 23:47:16 tbox Exp $ */ +/* $Id: keytable.c,v 1.41 2010-06-25 23:46:51 tbox Exp $ */ /*! \file */ @@ -31,41 +31,12 @@ #include #include -struct dns_keytable { - /* Unlocked. */ - unsigned int magic; - isc_mem_t *mctx; - isc_mutex_t lock; - isc_rwlock_t rwlock; - /* Locked by lock. */ - isc_uint32_t active_nodes; - /* Locked by rwlock. */ - isc_uint32_t references; - dns_rbt_t *table; -}; - -#define KEYTABLE_MAGIC ISC_MAGIC('K', 'T', 'b', 'l') -#define VALID_KEYTABLE(kt) ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC) - -struct dns_keynode { - unsigned int magic; - dst_key_t * key; - struct dns_keynode * next; -}; - -#define KEYNODE_MAGIC ISC_MAGIC('K', 'N', 'o', 'd') -#define VALID_KEYNODE(kn) ISC_MAGIC_VALID(kn, KEYNODE_MAGIC) - static void free_keynode(void *node, void *arg) { dns_keynode_t *keynode = node; isc_mem_t *mctx = arg; - REQUIRE(VALID_KEYNODE(keynode)); - dst_key_free(&keynode->key); - if (keynode->next != NULL) - free_keynode(keynode->next, mctx); - isc_mem_put(mctx, keynode, sizeof(dns_keynode_t)); + dns_keynode_detachall(mctx, &keynode); } isc_result_t @@ -116,7 +87,6 @@ dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep) { return (result); } - void dns_keytable_attach(dns_keytable_t *source, dns_keytable_t **targetp) { @@ -173,50 +143,224 @@ dns_keytable_detach(dns_keytable_t **keytablep) { *keytablep = NULL; } -isc_result_t -dns_keytable_add(dns_keytable_t *keytable, dst_key_t **keyp) { +static isc_result_t +insert(dns_keytable_t *keytable, isc_boolean_t managed, + dns_name_t *keyname, dst_key_t **keyp) +{ isc_result_t result; - dns_keynode_t *knode; + dns_keynode_t *knode = NULL; dns_rbtnode_t *node; - dns_name_t *keyname; - - /* - * Add '*keyp' to 'keytable'. - */ + REQUIRE(keyp == NULL || *keyp != NULL); REQUIRE(VALID_KEYTABLE(keytable)); - REQUIRE(keyp != NULL); - keyname = dst_key_name(*keyp); + result = dns_keynode_create(keytable->mctx, &knode); + if (result != ISC_R_SUCCESS) + return (result); - knode = isc_mem_get(keytable->mctx, sizeof(*knode)); - if (knode == NULL) - return (ISC_R_NOMEMORY); + knode->managed = managed; RWLOCK(&keytable->rwlock, isc_rwlocktype_write); node = NULL; result = dns_rbt_addnode(keytable->table, keyname, &node); - if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) { - knode->magic = KEYNODE_MAGIC; - knode->key = *keyp; - knode->next = node->data; + if (keyp != NULL) { + if (result == ISC_R_EXISTS) { + /* Key already in table? */ + dns_keynode_t *k; + for (k = node->data; k != NULL; k = k->next) { + if (k->key == NULL) { + k->key = *keyp; + break; + } + if (dst_key_compare(k->key, *keyp) == ISC_TRUE) + break; + } + + if (k == NULL) + result = ISC_R_SUCCESS; + else + dst_key_free(keyp); + } + + if (result == ISC_R_SUCCESS) { + knode->key = *keyp; + knode->next = node->data; + *keyp = NULL; + } + } + + if (result == ISC_R_SUCCESS) { node->data = knode; - *keyp = NULL; knode = NULL; - result = ISC_R_SUCCESS; } + /* Key was already there? That's the same as a success */ + if (result == ISC_R_EXISTS) + result = ISC_R_SUCCESS; + RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write); if (knode != NULL) - isc_mem_put(keytable->mctx, knode, sizeof(*knode)); + dns_keynode_detach(keytable->mctx, &knode); + + return (result); +} + +isc_result_t +dns_keytable_add(dns_keytable_t *keytable, isc_boolean_t managed, + dst_key_t **keyp) +{ + REQUIRE(keyp != NULL && *keyp != NULL); + return (insert(keytable, managed, dst_key_name(*keyp), keyp)); +} + +isc_result_t +dns_keytable_marksecure(dns_keytable_t *keytable, dns_name_t *name) { + return (insert(keytable, ISC_TRUE, name, NULL)); +} + +isc_result_t +dns_keytable_delete(dns_keytable_t *keytable, dns_name_t *keyname) { + isc_result_t result; + dns_rbtnode_t *node = NULL; + + REQUIRE(VALID_KEYTABLE(keytable)); + REQUIRE(keyname != NULL); + + RWLOCK(&keytable->rwlock, isc_rwlocktype_write); + result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL, + DNS_RBTFIND_NOOPTIONS, NULL, NULL); + if (result == ISC_R_SUCCESS) { + if (node->data != NULL) + result = dns_rbt_deletenode(keytable->table, + node, ISC_FALSE); + else + result = ISC_R_NOTFOUND; + } else if (result == DNS_R_PARTIALMATCH) + result = ISC_R_NOTFOUND; + RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write); return (result); } isc_result_t +dns_keytable_deletekeynode(dns_keytable_t *keytable, dst_key_t *dstkey) { + isc_result_t result; + dns_name_t *keyname; + dns_rbtnode_t *node = NULL; + dns_keynode_t *knode = NULL, **kprev = NULL; + + REQUIRE(VALID_KEYTABLE(keytable)); + REQUIRE(dstkey != NULL); + + keyname = dst_key_name(dstkey); + + RWLOCK(&keytable->rwlock, isc_rwlocktype_write); + result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL, + DNS_RBTFIND_NOOPTIONS, NULL, NULL); + + if (result == DNS_R_PARTIALMATCH) + result = ISC_R_NOTFOUND; + if (result != ISC_R_SUCCESS) + goto finish; + + if (node->data == NULL) { + result = ISC_R_NOTFOUND; + goto finish; + } + + knode = node->data; + if (knode->next == NULL && + (knode->key == NULL || + dst_key_compare(knode->key, dstkey) == ISC_TRUE)) { + result = dns_rbt_deletenode(keytable->table, node, ISC_FALSE); + goto finish; + } + + kprev = (dns_keynode_t **) &node->data; + while (knode != NULL) { + if (dst_key_compare(knode->key, dstkey) == ISC_TRUE) + break; + kprev = &knode->next; + knode = knode->next; + } + + if (knode != NULL) { + if (knode->key != NULL) + dst_key_free(&knode->key); + /* + * This is equivalent to: + * dns_keynode_attach(knode->next, &tmp); + * dns_keynode_detach(kprev); + * dns_keynode_attach(tmp, &kprev); + * dns_keynode_detach(&tmp); + */ + *kprev = knode->next; + knode->next = NULL; + dns_keynode_detach(keytable->mctx, &knode); + } else + result = DNS_R_PARTIALMATCH; + finish: + RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write); + return (result); +} + +isc_result_t +dns_keytable_find(dns_keytable_t *keytable, dns_name_t *keyname, + dns_keynode_t **keynodep) +{ + isc_result_t result; + dns_rbtnode_t *node = NULL; + + REQUIRE(VALID_KEYTABLE(keytable)); + REQUIRE(keyname != NULL); + REQUIRE(keynodep != NULL && *keynodep == NULL); + + RWLOCK(&keytable->rwlock, isc_rwlocktype_read); + result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL, + DNS_RBTFIND_NOOPTIONS, NULL, NULL); + if (result == ISC_R_SUCCESS) { + if (node->data != NULL) { + LOCK(&keytable->lock); + keytable->active_nodes++; + UNLOCK(&keytable->lock); + dns_keynode_attach(node->data, keynodep); + } else + result = ISC_R_NOTFOUND; + } else if (result == DNS_R_PARTIALMATCH) + result = ISC_R_NOTFOUND; + RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read); + + return (result); +} + +isc_result_t +dns_keytable_nextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode, + dns_keynode_t **nextnodep) +{ + /* + * Return the next key after 'keynode', regardless of + * properties. + */ + + REQUIRE(VALID_KEYTABLE(keytable)); + REQUIRE(VALID_KEYNODE(keynode)); + REQUIRE(nextnodep != NULL && *nextnodep == NULL); + + if (keynode->next == NULL) + return (ISC_R_NOTFOUND); + + dns_keynode_attach(keynode->next, nextnodep); + LOCK(&keytable->lock); + keytable->active_nodes++; + UNLOCK(&keytable->lock); + + return (ISC_R_SUCCESS); +} + +isc_result_t dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name, dns_secalg_t algorithm, dns_keytag_t tag, dns_keynode_t **keynodep) @@ -250,6 +394,10 @@ dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name, if (result == ISC_R_SUCCESS) { INSIST(data != NULL); for (knode = data; knode != NULL; knode = knode->next) { + if (knode->key == NULL) { + knode = NULL; + break; + } if (algorithm == dst_key_alg(knode->key) && tag == dst_key_id(knode->key)) break; @@ -258,7 +406,7 @@ dns_keytable_findkeynode(dns_keytable_t *keytable, dns_name_t *name, LOCK(&keytable->lock); keytable->active_nodes++; UNLOCK(&keytable->lock); - *keynodep = knode; + dns_keynode_attach(knode, keynodep); } else result = DNS_R_PARTIALMATCH; } else if (result == DNS_R_PARTIALMATCH) @@ -286,6 +434,10 @@ dns_keytable_findnextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode, REQUIRE(nextnodep != NULL && *nextnodep == NULL); for (knode = keynode->next; knode != NULL; knode = knode->next) { + if (knode->key == NULL) { + knode = NULL; + break; + } if (dst_key_alg(keynode->key) == dst_key_alg(knode->key) && dst_key_id(keynode->key) == dst_key_id(knode->key)) break; @@ -295,7 +447,7 @@ dns_keytable_findnextkeynode(dns_keytable_t *keytable, dns_keynode_t *keynode, keytable->active_nodes++; UNLOCK(&keytable->lock); result = ISC_R_SUCCESS; - *nextnodep = knode; + dns_keynode_attach(knode, nextnodep); } else result = ISC_R_NOTFOUND; @@ -331,6 +483,25 @@ dns_keytable_finddeepestmatch(dns_keytable_t *keytable, dns_name_t *name, } void +dns_keytable_attachkeynode(dns_keytable_t *keytable, dns_keynode_t *source, + dns_keynode_t **target) +{ + /* + * Give back a keynode found via dns_keytable_findkeynode(). + */ + + REQUIRE(VALID_KEYTABLE(keytable)); + REQUIRE(VALID_KEYNODE(source)); + REQUIRE(target != NULL && *target == NULL); + + LOCK(&keytable->lock); + keytable->active_nodes++; + UNLOCK(&keytable->lock); + + dns_keynode_attach(source, target); +} + +void dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep) { /* @@ -345,7 +516,7 @@ dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep) keytable->active_nodes--; UNLOCK(&keytable->lock); - *keynodep = NULL; + dns_keynode_detach(keytable->mctx, keynodep); } isc_result_t @@ -382,6 +553,44 @@ dns_keytable_issecuredomain(dns_keytable_t *keytable, dns_name_t *name, return (result); } +isc_result_t +dns_keytable_dump(dns_keytable_t *keytable, FILE *fp) +{ + isc_result_t result; + dns_keynode_t *knode; + dns_rbtnode_t *node; + dns_rbtnodechain_t chain; + + REQUIRE(VALID_KEYTABLE(keytable)); + + RWLOCK(&keytable->rwlock, isc_rwlocktype_read); + dns_rbtnodechain_init(&chain, keytable->mctx); + result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL); + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) + goto cleanup; + for (;;) { + char pbuf[DST_KEY_FORMATSIZE]; + + dns_rbtnodechain_current(&chain, NULL, NULL, &node); + for (knode = node->data; knode != NULL; knode = knode->next) { + dst_key_format(knode->key, pbuf, sizeof(pbuf)); + fprintf(fp, "%s ; %s\n", pbuf, + knode->managed ? "managed" : "trusted"); + } + result = dns_rbtnodechain_next(&chain, NULL, NULL); + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + break; + } + } + + cleanup: + dns_rbtnodechain_invalidate(&chain); + RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read); + return (result); +} + dst_key_t * dns_keynode_key(dns_keynode_t *keynode) { @@ -393,3 +602,71 @@ dns_keynode_key(dns_keynode_t *keynode) { return (keynode->key); } + +isc_boolean_t +dns_keynode_managed(dns_keynode_t *keynode) { + /* + * Is this a managed key? + */ + REQUIRE(VALID_KEYNODE(keynode)); + + return (keynode->managed); +} + +isc_result_t +dns_keynode_create(isc_mem_t *mctx, dns_keynode_t **target) { + isc_result_t result; + dns_keynode_t *knode = NULL; + + REQUIRE(target != NULL && *target == NULL); + + knode = isc_mem_get(mctx, sizeof(dns_keynode_t)); + if (knode == NULL) + return (ISC_R_NOMEMORY); + + knode->magic = KEYNODE_MAGIC; + knode->managed = ISC_FALSE; + knode->key = NULL; + knode->next = NULL; + + result = isc_refcount_init(&knode->refcount, 1); + if (result != ISC_R_SUCCESS) + return (result); + + *target = knode; + return (ISC_R_SUCCESS); +} + +void +dns_keynode_attach(dns_keynode_t *source, dns_keynode_t **target) { + REQUIRE(VALID_KEYNODE(source)); + isc_refcount_increment(&source->refcount, NULL); + *target = source; +} + +void +dns_keynode_detach(isc_mem_t *mctx, dns_keynode_t **keynode) { + unsigned int refs; + dns_keynode_t *node = *keynode; + REQUIRE(VALID_KEYNODE(node)); + isc_refcount_decrement(&node->refcount, &refs); + if (refs == 0) { + if (node->key != NULL) + dst_key_free(&node->key); + isc_refcount_destroy(&node->refcount); + isc_mem_put(mctx, node, sizeof(dns_keynode_t)); + } + *keynode = NULL; +} + +void +dns_keynode_detachall(isc_mem_t *mctx, dns_keynode_t **keynode) { + dns_keynode_t *next = NULL, *node = *keynode; + REQUIRE(VALID_KEYNODE(node)); + while (node != NULL) { + next = node->next; + dns_keynode_detach(mctx, &node); + node = next; + } + *keynode = NULL; +} diff --git a/lib/dns/lib.c b/lib/dns/lib.c index 761be56..6953c88 100644 --- a/lib/dns/lib.c +++ b/lib/dns/lib.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lib.c,v 1.16 2007-06-19 23:47:16 tbox Exp $ */ +/* $Id: lib.c,v 1.19 2009-09-03 00:12:23 each Exp $ */ /*! \file */ @@ -23,11 +23,20 @@ #include -#include +#include +#include #include +#include +#include #include +#include +#include #include +#include + +#include + /*** *** Globals @@ -63,3 +72,97 @@ dns_lib_initmsgcat(void) { RUNTIME_CHECK(isc_once_do(&msgcat_once, open_msgcat) == ISC_R_SUCCESS); } + +static isc_once_t init_once = ISC_ONCE_INIT; +static isc_mem_t *dns_g_mctx = NULL; +#ifndef BIND9 +static dns_dbimplementation_t *dbimp = NULL; +#endif +static isc_boolean_t initialize_done = ISC_FALSE; +static isc_mutex_t reflock; +static unsigned int references = 0; + +static void +initialize(void) { + isc_result_t result; + + REQUIRE(initialize_done == ISC_FALSE); + + result = isc_mem_create(0, 0, &dns_g_mctx); + if (result != ISC_R_SUCCESS) + return; + dns_result_register(); +#ifndef BIND9 + result = dns_ecdb_register(dns_g_mctx, &dbimp); + if (result != ISC_R_SUCCESS) + goto cleanup_mctx; +#endif + result = isc_hash_create(dns_g_mctx, NULL, DNS_NAME_MAXWIRE); + if (result != ISC_R_SUCCESS) + goto cleanup_db; + + result = dst_lib_init(dns_g_mctx, NULL, 0); + if (result != ISC_R_SUCCESS) + goto cleanup_hash; + + result = isc_mutex_init(&reflock); + if (result != ISC_R_SUCCESS) + goto cleanup_dst; + + initialize_done = ISC_TRUE; + return; + + cleanup_dst: + dst_lib_destroy(); + cleanup_hash: + isc_hash_destroy(); + cleanup_db: +#ifndef BIND9 + dns_ecdb_unregister(&dbimp); + cleanup_mctx: +#endif + isc_mem_detach(&dns_g_mctx); +} + +isc_result_t +dns_lib_init(void) { + isc_result_t result; + + /* + * Since this routine is expected to be used by a normal application, + * it should be better to return an error, instead of an emergency + * abort, on any failure. + */ + result = isc_once_do(&init_once, initialize); + if (result != ISC_R_SUCCESS) + return (result); + + if (!initialize_done) + return (ISC_R_FAILURE); + + LOCK(&reflock); + references++; + UNLOCK(&reflock); + + return (ISC_R_SUCCESS); +} + +void +dns_lib_shutdown(void) { + isc_boolean_t cleanup_ok = ISC_FALSE; + + LOCK(&reflock); + if (--references == 0) + cleanup_ok = ISC_TRUE; + UNLOCK(&reflock); + + if (!cleanup_ok) + return; + + dst_lib_destroy(); + isc_hash_destroy(); +#ifndef BIND9 + dns_ecdb_unregister(&dbimp); +#endif + isc_mem_detach(&dns_g_mctx); +} diff --git a/lib/dns/log.c b/lib/dns/log.c index 5b3ee32..9de5976 100644 --- a/lib/dns/log.c +++ b/lib/dns/log.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: log.c,v 1.45 2007-06-18 23:47:40 tbox Exp $ */ +/* $Id: log.c,v 1.47 2009-12-18 23:49:03 tbox Exp $ */ /*! \file */ @@ -79,6 +79,7 @@ LIBDNS_EXTERNAL_DATA isc_logmodule_t dns_modules[] = { { "dns/hints", 0 }, { "dns/acache", 0 }, { "dns/dlz", 0 }, + { "dns/dnssec", 0 }, { NULL, 0 } }; diff --git a/lib/dns/master.c b/lib/dns/master.c index 9c6d3b8..e90a74c 100644 --- a/lib/dns/master.c +++ b/lib/dns/master.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: master.c,v 1.171.120.2 2009-01-18 23:47:40 tbox Exp $ */ +/* $Id: master.c,v 1.178 2009-09-01 00:22:26 jinmei Exp $ */ /*! \file */ @@ -85,7 +85,11 @@ */ #define TOKENSIZ (8*1024) -#define DNS_MASTER_BUFSZ 2048 +/*% + * Buffers sizes for $GENERATE. + */ +#define DNS_MASTER_LHS 2048 +#define DNS_MASTER_RHS MINTSIZ typedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t; @@ -614,6 +618,57 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, return (result); } +static const char *hex = "0123456789abcdef0123456789ABCDEF"; + +/*% + * Convert value into a nibble sequence from least significant to most + * significant nibble. Zero fill upper most significant nibbles if + * required to make the width. + * + * Returns the number of characters that should have been written without + * counting the terminating NUL. + */ +static unsigned int +nibbles(char *numbuf, size_t length, unsigned int width, char mode, int value) { + unsigned int count = 0; + + /* + * This reserve space for the NUL string terminator. + */ + if (length > 0U) { + *numbuf = '\0'; + length--; + } + do { + char val = hex[(value & 0x0f) + ((mode == 'n') ? 0 : 16)]; + value >>= 4; + if (length > 0U) { + *numbuf++ = val; + *numbuf = '\0'; + length--; + } + if (width > 0) + width--; + count++; + /* + * If width is non zero then we need to add a label seperator. + * If value is non zero then we need to add another label and + * that requires a label seperator. + */ + if (width > 0 || value != 0) { + if (length > 0U) { + *numbuf++ = '.'; + *numbuf = '\0'; + length--; + } + if (width > 0) + width--; + count++; + } + } while (value != 0 || width > 0); + return (count); +} + static isc_result_t genname(char *name, int it, char *buffer, size_t length) { char fmt[sizeof("%04000000000d")]; @@ -624,6 +679,7 @@ genname(char *name, int it, char *buffer, size_t length) { isc_textregion_t r; unsigned int n; unsigned int width; + isc_boolean_t nibblemode; r.base = buffer; r.length = length; @@ -638,10 +694,11 @@ genname(char *name, int it, char *buffer, size_t length) { isc_textregion_consume(&r, 1); continue; } + nibblemode = ISC_FALSE; strcpy(fmt, "%d"); /* Get format specifier. */ if (*name == '{' ) { - n = sscanf(name, "{%d,%u,%1[doxX]}", + n = sscanf(name, "{%d,%u,%1[doxXnN]}", &delta, &width, mode); switch (n) { case 1: @@ -651,6 +708,8 @@ genname(char *name, int it, char *buffer, size_t length) { "%%0%ud", width); break; case 3: + if (mode[0] == 'n' || mode[0] == 'N') + nibblemode = ISC_TRUE; n = snprintf(fmt, sizeof(fmt), "%%0%u%c", width, mode[0]); break; @@ -663,7 +722,12 @@ genname(char *name, int it, char *buffer, size_t length) { while (*name != '\0' && *name++ != '}') continue; } - n = snprintf(numbuf, sizeof(numbuf), fmt, it + delta); + if (nibblemode) + n = nibbles(numbuf, sizeof(numbuf), width, + mode[0], it + delta); + else + n = snprintf(numbuf, sizeof(numbuf), fmt, + it + delta); if (n >= sizeof(numbuf)) return (ISC_R_NOSPACE); cp = numbuf; @@ -746,8 +810,8 @@ generate(dns_loadctx_t *lctx, char *range, char *lhs, char *gtype, char *rhs, ISC_LIST_INIT(head); target_mem = isc_mem_get(lctx->mctx, target_size); - rhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_BUFSZ); - lhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_BUFSZ); + rhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_RHS); + lhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_LHS); if (target_mem == NULL || rhsbuf == NULL || lhsbuf == NULL) { result = ISC_R_NOMEMORY; goto error_cleanup; @@ -778,35 +842,13 @@ generate(dns_loadctx_t *lctx, char *range, char *lhs, char *gtype, char *rhs, goto insist_cleanup; } - switch (type) { - case dns_rdatatype_ns: - case dns_rdatatype_ptr: - case dns_rdatatype_cname: - case dns_rdatatype_dname: - break; - - case dns_rdatatype_a: - case dns_rdatatype_aaaa: - if (lctx->zclass == dns_rdataclass_in || - lctx->zclass == dns_rdataclass_ch || - lctx->zclass == dns_rdataclass_hs) - break; - /* FALLTHROUGH */ - default: - (*callbacks->error)(callbacks, - "%s: %s:%lu: unsupported type '%s'", - "$GENERATE", source, line, gtype); - result = ISC_R_NOTIMPLEMENTED; - goto error_cleanup; - } - ISC_LIST_INIT(rdatalist.rdata); ISC_LINK_INIT(&rdatalist, link); for (i = start; i <= stop; i += step) { - result = genname(lhs, i, lhsbuf, DNS_MASTER_BUFSZ); + result = genname(lhs, i, lhsbuf, DNS_MASTER_LHS); if (result != ISC_R_SUCCESS) goto error_cleanup; - result = genname(rhs, i, rhsbuf, DNS_MASTER_BUFSZ); + result = genname(rhs, i, rhsbuf, DNS_MASTER_RHS); if (result != ISC_R_SUCCESS) goto error_cleanup; @@ -820,6 +862,7 @@ generate(dns_loadctx_t *lctx, char *range, char *lhs, char *gtype, char *rhs, if ((lctx->options & DNS_MASTER_ZONE) != 0 && (lctx->options & DNS_MASTER_SLAVE) == 0 && + (lctx->options & DNS_MASTER_KEY) == 0 && !dns_name_issubdomain(owner, lctx->top)) { char namebuf[DNS_NAME_FORMATSIZE]; @@ -880,9 +923,9 @@ generate(dns_loadctx_t *lctx, char *range, char *lhs, char *gtype, char *rhs, if (target_mem != NULL) isc_mem_put(lctx->mctx, target_mem, target_size); if (lhsbuf != NULL) - isc_mem_put(lctx->mctx, lhsbuf, DNS_MASTER_BUFSZ); + isc_mem_put(lctx->mctx, lhsbuf, DNS_MASTER_LHS); if (rhsbuf != NULL) - isc_mem_put(lctx->mctx, rhsbuf, DNS_MASTER_BUFSZ); + isc_mem_put(lctx->mctx, rhsbuf, DNS_MASTER_RHS); return (result); } @@ -1270,7 +1313,8 @@ load_text(dns_loadctx_t *lctx) { goto log_and_cleanup; } /* RHS */ - GETTOKEN(lctx->lex, 0, &token, ISC_FALSE); + GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING, + &token, ISC_FALSE); rhs = isc_mem_strdup(mctx, DNS_AS_STR(token)); if (rhs == NULL) { result = ISC_R_NOMEMORY; @@ -1338,7 +1382,7 @@ load_text(dns_loadctx_t *lctx) { isc_buffer_setactive(&buffer, token.value.as_region.length); result = dns_name_fromtext(new_name, &buffer, - ictx->origin, ISC_FALSE, NULL); + ictx->origin, 0, NULL); if (MANYERRS(lctx, result)) { SETRESULT(lctx, result); LOGIT(result); @@ -1459,6 +1503,7 @@ load_text(dns_loadctx_t *lctx) { } if ((lctx->options & DNS_MASTER_ZONE) != 0 && (lctx->options & DNS_MASTER_SLAVE) == 0 && + (lctx->options & DNS_MASTER_KEY) == 0 && !dns_name_issubdomain(new_name, lctx->top)) { char namebuf[DNS_NAME_FORMATSIZE]; diff --git a/lib/dns/masterdump.c b/lib/dns/masterdump.c index d6befb5..e2adf9b 100644 --- a/lib/dns/masterdump.c +++ b/lib/dns/masterdump.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: masterdump.c,v 1.94.50.3.18.3 2011-06-21 20:13:22 each Exp $ */ +/* $Id: masterdump.c,v 1.99.328.3 2011-06-21 20:15:47 each Exp $ */ /*! \file */ @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,11 @@ return (_r); \ } while (0) +#define CHECK(x) do { \ + if ((x) != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + struct dns_master_style { unsigned int flags; /* DNS_STYLEFLAG_* */ unsigned int ttl_column; @@ -156,6 +162,7 @@ static char spaces[N_SPACES+1] = " "; #define N_TABS 10 static char tabs[N_TABS+1] = "\t\t\t\t\t\t\t\t\t\t"; +#ifdef BIND9 struct dns_dumpctx { unsigned int magic; isc_mem_t *mctx; @@ -183,6 +190,7 @@ struct dns_dumpctx { dns_totext_ctx_t *ctx, isc_buffer_t *buffer, FILE *f); }; +#endif /* BIND9 */ #define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) @@ -336,6 +344,52 @@ str_totext(const char *source, isc_buffer_t *target) { return (ISC_R_SUCCESS); } +static isc_result_t +ncache_summary(dns_rdataset_t *rdataset, isc_boolean_t omit_final_dot, + isc_buffer_t *target) +{ + isc_result_t result = ISC_R_SUCCESS; + dns_rdataset_t rds; + dns_name_t name; + + dns_rdataset_init(&rds); + dns_name_init(&name, NULL); + + do { + dns_ncache_current(rdataset, &name, &rds); + for (result = dns_rdataset_first(&rds); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rds)) { + CHECK(str_totext("; ", target)); + CHECK(dns_name_totext(&name, omit_final_dot, target)); + CHECK(str_totext(" ", target)); + CHECK(dns_rdatatype_totext(rds.type, target)); + if (rds.type == dns_rdatatype_rrsig) { + CHECK(str_totext(" ", target)); + CHECK(dns_rdatatype_totext(rds.covers, target)); + CHECK(str_totext(" ...\n", target)); + } else { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_current(&rds, &rdata); + CHECK(str_totext(" ", target)); + CHECK(dns_rdata_tofmttext(&rdata, dns_rootname, + 0, 0, " ", target)); + CHECK(str_totext("\n", target)); + } + } + dns_rdataset_disassociate(&rds); + result = dns_rdataset_next(rdataset); + } while (result == ISC_R_SUCCESS); + + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + cleanup: + if (dns_rdataset_isassociated(&rds)) + dns_rdataset_disassociate(&rds); + + return (result); +} + /* * Convert 'rdataset' to master file text format according to 'ctx', * storing the result in 'target'. If 'owner_name' is NULL, it @@ -462,6 +516,13 @@ rdataset_totext(dns_rdataset_t *rdataset, RETERR(str_totext(";-$NXDOMAIN\n", target)); else RETERR(str_totext(";-$NXRRSET\n", target)); + /* + * Print a summary of the cached records which make + * up the negative response. + */ + RETERR(ncache_summary(rdataset, omit_final_dot, + target)); + break; } else { dns_rdata_t rdata = DNS_RDATA_INIT; isc_region_t r; @@ -637,6 +698,7 @@ dns_master_questiontotext(dns_name_t *owner_name, ISC_FALSE, target)); } +#ifdef BIND9 /* * Print an rdataset. 'buffer' is a scratch buffer, which must have been * dynamically allocated by the caller. It must be large enough to @@ -1692,6 +1754,7 @@ dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, return (result); } +#endif /* BIND9 */ isc_result_t dns_master_stylecreate(dns_master_style_t **stylep, unsigned int flags, diff --git a/lib/dns/message.c b/lib/dns/message.c index 2023741..b58c139 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: message.c,v 1.245.50.7.6.3 2011-06-21 20:13:22 each Exp $ */ +/* $Id: message.c,v 1.254.186.3 2011-06-21 20:15:47 each Exp $ */ /*! \file */ @@ -1804,6 +1804,36 @@ wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) { return (ISC_TRUE); } +#ifdef ALLOW_FILTER_AAAA_ON_V4 +/* + * Decide whether to not answer with an AAAA record and its RRSIG + */ +static inline isc_boolean_t +norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options) +{ + switch (rdataset->type) { + case dns_rdatatype_aaaa: + if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0) + return (ISC_FALSE); + break; + + case dns_rdatatype_rrsig: + if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 || + rdataset->covers != dns_rdatatype_aaaa) + return (ISC_FALSE); + break; + + default: + return (ISC_FALSE); + } + + if (rdataset->rdclass != dns_rdataclass_in) + return (ISC_FALSE); + + return (ISC_TRUE); +} + +#endif isc_result_t dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, unsigned int options) @@ -1931,6 +1961,23 @@ dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, preferred_glue)) goto next; +#ifdef ALLOW_FILTER_AAAA_ON_V4 + /* + * Suppress AAAAs if asked and we are + * not doing DNSSEC or are breaking DNSSEC. + * Say so in the AD bit if we break DNSSEC. + */ + if (norender_rdataset(rdataset, options) && + sectionid != DNS_SECTION_QUESTION) { + if (sectionid == DNS_SECTION_ANSWER || + sectionid == DNS_SECTION_AUTHORITY) + msg->flags &= ~DNS_MESSAGEFLAG_AD; + if (OPTOUT(rdataset)) + msg->flags &= ~DNS_MESSAGEFLAG_AD; + goto next; + } + +#endif st = *(msg->buffer); count = 0; @@ -3071,6 +3118,7 @@ dns_message_sectiontotext(dns_message_t *msg, dns_section_t section, dns_name_t *name, empty_name; dns_rdataset_t *rdataset; isc_result_t result; + isc_boolean_t seensoa = ISC_FALSE; REQUIRE(DNS_MESSAGE_VALID(msg)); REQUIRE(target != NULL); @@ -3100,6 +3148,15 @@ dns_message_sectiontotext(dns_message_t *msg, dns_section_t section, for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { + if (section == DNS_SECTION_ANSWER && + rdataset->type == dns_rdatatype_soa) { + if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0) + continue; + if (seensoa && + (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0) + continue; + seensoa = ISC_TRUE; + } if (section == DNS_SECTION_QUESTION) { ADD_STRING(target, ";"); result = dns_master_questiontotext(name, diff --git a/lib/dns/name.c b/lib/dns/name.c index 80864b8..f88f281 100644 --- a/lib/dns/name.c +++ b/lib/dns/name.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: name.c,v 1.165.120.3 2010-07-09 05:15:05 each Exp $ */ +/* $Id: name.c,v 1.174 2011-01-13 04:59:25 tbox Exp $ */ /*! \file */ @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -1018,10 +1019,9 @@ dns_name_toregion(dns_name_t *name, isc_region_t *r) { DNS_NAME_TOREGION(name, r); } - isc_result_t dns_name_fromtext(dns_name_t *name, isc_buffer_t *source, - dns_name_t *origin, unsigned int options, + const dns_name_t *origin, unsigned int options, isc_buffer_t *target) { unsigned char *ndata, *label; @@ -2360,6 +2360,75 @@ dns_name_format(dns_name_t *name, char *cp, unsigned int size) { snprintf(cp, size, ""); } +/* + * dns_name_tostring() -- similar to dns_name_format() but allocates its own + * memory. + */ +isc_result_t +dns_name_tostring(dns_name_t *name, char **target, isc_mem_t *mctx) { + isc_result_t result; + isc_buffer_t buf; + isc_region_t reg; + char *p, txt[DNS_NAME_FORMATSIZE]; + + REQUIRE(VALID_NAME(name)); + REQUIRE(target != NULL && *target == NULL); + + isc_buffer_init(&buf, txt, sizeof(txt)); + result = dns_name_totext(name, ISC_FALSE, &buf); + if (result != ISC_R_SUCCESS) + return (result); + + isc_buffer_usedregion(&buf, ®); + p = isc_mem_allocate(mctx, reg.length + 1); + memcpy(p, (char *) reg.base, (int) reg.length); + p[reg.length] = '\0'; + + *target = p; + return (ISC_R_SUCCESS); +} + +/* + * dns_name_fromstring() -- convert directly from a string to a name, + * allocating memory as needed + */ +isc_result_t +dns_name_fromstring(dns_name_t *target, const char *src, unsigned int options, + isc_mem_t *mctx) +{ + return (dns_name_fromstring2(target, src, dns_rootname, options, mctx)); +} + +isc_result_t +dns_name_fromstring2(dns_name_t *target, const char *src, + const dns_name_t *origin, unsigned int options, + isc_mem_t *mctx) +{ + isc_result_t result; + isc_buffer_t buf; + dns_fixedname_t fn; + dns_name_t *name; + + REQUIRE(src != NULL); + + isc_buffer_init(&buf, src, strlen(src)); + isc_buffer_add(&buf, strlen(src)); + if (BINDABLE(target) && target->buffer != NULL) + name = target; + else { + dns_fixedname_init(&fn); + name = dns_fixedname_name(&fn); + } + + result = dns_name_fromtext(name, &buf, origin, options, NULL); + if (result != ISC_R_SUCCESS) + return (result); + + if (name != target) + result = dns_name_dupwithoffsets(name, mctx, target); + return (result); +} + isc_result_t dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) { unsigned char *ndata; diff --git a/lib/dns/ncache.c b/lib/dns/ncache.c index f1fc323..420a118 100644 --- a/lib/dns/ncache.c +++ b/lib/dns/ncache.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ncache.c,v 1.43.48.7.6.3 2011-06-21 20:13:22 each Exp $ */ +/* $Id: ncache.c,v 1.50.124.1.2.3 2011-06-21 20:15:47 each Exp $ */ /*! \file */ @@ -35,7 +35,7 @@ #define DNS_NCACHE_RDATA 20U /* - * The format of an ncache rdata is a sequence of one or more records of + * The format of an ncache rdata is a sequence of zero or more records of * the following format: * * owner name @@ -223,42 +223,6 @@ dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, return (result); if (trust == 0xffff) { - /* - * We didn't find any authority data from which to create a - * negative cache rdataset. In particular, we have no SOA. - * - * We trust that the caller wants negative caching, so this - * means we have a "type 3 nxdomain" or "type 3 nodata" - * response (see RFC2308 for details). - * - * We will now build a suitable negative cache rdataset that - * will cause zero bytes to be emitted when converted to - * wire format. - */ - - /* - * The ownername must exist, but it doesn't matter what value - * it has. We use the root name. - */ - dns_name_toregion(dns_rootname, &r); - result = isc_buffer_copyregion(&buffer, &r); - if (result != ISC_R_SUCCESS) - return (result); - /* - * Copy the type and a zero rdata count to the buffer. - */ - isc_buffer_availableregion(&buffer, &r); - if (r.length < 5) - return (ISC_R_NOSPACE); - isc_buffer_putuint16(&buffer, 0); /* type */ - /* - * RFC2308, section 5, says that negative answers without - * SOAs should not be cached. - */ - ttl = 0; - /* - * Set trust. - */ if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 && message->counts[DNS_SECTION_ANSWER] == 0) { /* @@ -268,22 +232,7 @@ dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, trust = dns_trust_authauthority; } else trust = dns_trust_additional; - isc_buffer_putuint8(&buffer, (unsigned char)trust); /* trust */ - isc_buffer_putuint16(&buffer, 0); /* count */ - - /* - * Now add it to the cache. - */ - if (next >= DNS_NCACHE_RDATA) - return (ISC_R_NOSPACE); - dns_rdata_init(&rdata[next]); - isc_buffer_remainingregion(&buffer, &r); - rdata[next].data = r.base; - rdata[next].length = r.length; - rdata[next].rdclass = ncrdatalist.rdclass; - rdata[next].type = 0; - rdata[next].flags = 0; - ISC_LIST_APPEND(ncrdatalist.rdata, &rdata[next], link); + ttl = 0; } INSIST(trust != 0xffff); diff --git a/lib/dns/nsec.c b/lib/dns/nsec.c index 7d93ecc..94c5163 100644 --- a/lib/dns/nsec.c +++ b/lib/dns/nsec.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsec.c,v 1.11.48.2 2009-01-06 23:47:26 tbox Exp $ */ +/* $Id: nsec.c,v 1.13 2009-01-06 23:47:57 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/nsec3.c b/lib/dns/nsec3.c index 9c85781..e75e744 100644 --- a/lib/dns/nsec3.c +++ b/lib/dns/nsec3.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2008, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2006, 2008-2010 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsec3.c,v 1.6.12.4 2009-11-03 23:47:46 tbox Exp $ */ +/* $Id: nsec3.c,v 1.19.96.1 2011-06-21 20:15:48 each Exp $ */ #include @@ -28,6 +28,8 @@ #include #include +#include +#include #include #include #include @@ -472,7 +474,6 @@ delete(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, return (result); } -#ifndef RFC5155_STRICT static isc_boolean_t better_param(dns_rdataset_t *nsec3paramset, dns_rdata_t *param) { dns_rdataset_t rdataset; @@ -487,7 +488,17 @@ better_param(dns_rdataset_t *nsec3paramset, dns_rdata_t *param) { result == ISC_R_SUCCESS; result = dns_rdataset_next(&rdataset)) { dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdataset_current(&rdataset, &rdata); + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + + if (rdataset.type != dns_rdatatype_nsec3param) { + dns_rdata_t tmprdata = DNS_RDATA_INIT; + dns_rdataset_current(&rdataset, &tmprdata); + if (!dns_nsec3param_fromprivate(&tmprdata, &rdata, + buf, sizeof(buf))) + continue; + } else + dns_rdataset_current(&rdataset, &rdata); + if (rdata.length != param->length) continue; if (rdata.data[0] != param->data[0] || @@ -505,7 +516,6 @@ better_param(dns_rdataset_t *nsec3paramset, dns_rdata_t *param) { dns_rdataset_disassociate(&rdataset); return (ISC_FALSE); } -#endif static isc_result_t find_nsec3(dns_rdata_nsec3_t *nsec3, dns_rdataset_t *rdataset, @@ -548,7 +558,7 @@ dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, dns_rdataset_t rdataset; int pass; isc_boolean_t exists; - isc_boolean_t remove_unsecure = ISC_FALSE; + isc_boolean_t maybe_remove_unsecure = ISC_FALSE; isc_uint8_t flags; isc_buffer_t buffer; isc_result_t result; @@ -629,8 +639,12 @@ dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, */ if (!unsecure) goto addnsec3; - else - remove_unsecure = ISC_TRUE; + else if (CREATE(nsec3param->flags) && OPTOUT(flags)) { + result = dns_nsec3_delnsec3(db, version, name, + nsec3param, diff); + goto failure; + } else + maybe_remove_unsecure = ISC_TRUE; } else { dns_rdataset_disassociate(&rdataset); if (result != ISC_R_NOMORE) @@ -666,26 +680,19 @@ dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, if (result != ISC_R_SUCCESS) goto failure; - if (remove_unsecure) { + if (maybe_remove_unsecure) { dns_rdataset_disassociate(&rdataset); /* - * We have found the previous NSEC3 record and can now - * see if the existing NSEC3 record needs to be - * updated or deleted. + * If we have OPTOUT set in the previous NSEC3 record + * we actually need to delete the NSEC3 record. + * Otherwise we just need to replace the NSEC3 record. */ - if (!OPTOUT(nsec3.flags)) { - /* - * Just update the NSEC3 record. - */ - goto addnsec3; - } else { - /* - * This is actually a deletion not a add. - */ + if (OPTOUT(nsec3.flags)) { result = dns_nsec3_delnsec3(db, version, name, nsec3param, diff); goto failure; } + goto addnsec3; } else { /* * Is this is a unsecure delegation we are adding? @@ -928,17 +935,323 @@ dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_current(&rdataset, &rdata); - dns_rdata_tostruct(&rdata, &nsec3param, NULL); + CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); + + if (nsec3param.flags != 0) + continue; + /* + * We have a active chain. Update it. + */ + CHECK(dns_nsec3_addnsec3(db, version, name, &nsec3param, + nsecttl, unsecure, diff)); + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + failure: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + + return (result); +} + +isc_boolean_t +dns_nsec3param_fromprivate(dns_rdata_t *src, dns_rdata_t *target, + unsigned char *buf, size_t buflen) +{ + dns_decompress_t dctx; + isc_result_t result; + isc_buffer_t buf1; + isc_buffer_t buf2; + + /* + * Algorithm 0 (reserved by RFC 4034) is used to identify + * NSEC3PARAM records from DNSKEY pointers. + */ + if (src->length < 1 || src->data[0] != 0) + return (ISC_FALSE); + + isc_buffer_init(&buf1, src->data + 1, src->length - 1); + isc_buffer_add(&buf1, src->length - 1); + isc_buffer_setactive(&buf1, src->length - 1); + isc_buffer_init(&buf2, buf, buflen); + dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE); + result = dns_rdata_fromwire(target, src->rdclass, + dns_rdatatype_nsec3param, + &buf1, &dctx, 0, &buf2); + dns_decompress_invalidate(&dctx); + + return (ISC_TF(result == ISC_R_SUCCESS)); +} + +void +dns_nsec3param_toprivate(dns_rdata_t *src, dns_rdata_t *target, + dns_rdatatype_t privatetype, + unsigned char *buf, size_t buflen) +{ + REQUIRE(buflen >= src->length + 1); + + REQUIRE(DNS_RDATA_INITIALIZED(target)); + + memcpy(buf + 1, src->data, src->length); + buf[0] = 0; + target->data = buf; + target->length = src->length + 1; + target->type = privatetype; + target->rdclass = src->rdclass; + target->flags = 0; + ISC_LINK_INIT(target, link); +} + +#ifdef BIND9 +static isc_result_t +rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + const dns_rdata_t *rdata, isc_boolean_t *flag) +{ + dns_rdataset_t rdataset; + dns_dbnode_t *node = NULL; + isc_result_t result; + + dns_rdataset_init(&rdataset); + if (rdata->type == dns_rdatatype_nsec3) + CHECK(dns_db_findnsec3node(db, name, ISC_FALSE, &node)); + else + CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); + result = dns_db_findrdataset(db, node, ver, rdata->type, 0, + (isc_stdtime_t) 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) { + *flag = ISC_FALSE; + result = ISC_R_SUCCESS; + goto failure; + } + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t myrdata = DNS_RDATA_INIT; + dns_rdataset_current(&rdataset, &myrdata); + if (!dns_rdata_casecompare(&myrdata, rdata)) + break; + } + dns_rdataset_disassociate(&rdataset); + if (result == ISC_R_SUCCESS) { + *flag = ISC_TRUE; + } else if (result == ISC_R_NOMORE) { + *flag = ISC_FALSE; + result = ISC_R_SUCCESS; + } + + failure: + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); +} +#endif + +#ifdef BIND9 +isc_result_t +dns_nsec3param_deletechains(dns_db_t *db, dns_dbversion_t *ver, + dns_zone_t *zone, dns_diff_t *diff) +{ + dns_dbnode_t *node = NULL; + dns_difftuple_t *tuple = NULL; + dns_name_t next; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_t rdataset; + isc_boolean_t flag; + isc_result_t result = ISC_R_SUCCESS; + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE + 1]; + dns_name_t *origin = dns_zone_getorigin(zone); + dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); + + dns_name_init(&next, NULL); + dns_rdataset_init(&rdataset); + + result = dns_db_getoriginnode(db, &node); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Cause all NSEC3 chains to be deleted. + */ + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, + 0, (isc_stdtime_t) 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) + goto try_private; + if (result != ISC_R_SUCCESS) + goto failure; + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t private = DNS_RDATA_INIT; + + dns_rdataset_current(&rdataset, &rdata); + + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, origin, + rdataset.ttl, &rdata, &tuple)); + CHECK(do_one_tuple(&tuple, db, ver, diff)); + INSIST(tuple == NULL); + + dns_nsec3param_toprivate(&rdata, &private, privatetype, + buf, sizeof(buf)); + buf[2] = DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC; + + CHECK(rr_exists(db, ver, origin, &private, &flag)); + + if (!flag) { + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, + origin, 0, &private, + &tuple)); + CHECK(do_one_tuple(&tuple, db, ver, diff)); + INSIST(tuple == NULL); + } + dns_rdata_reset(&rdata); + } + if (result != ISC_R_NOMORE) + goto failure; + + dns_rdataset_disassociate(&rdataset); + + try_private: + if (privatetype == 0) + goto success; + result = dns_db_findrdataset(db, node, ver, privatetype, 0, + (isc_stdtime_t) 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) + goto success; + if (result != ISC_R_SUCCESS) + goto failure; + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdataset_current(&rdataset, &rdata); + INSIST(rdata.length <= sizeof(buf)); + memcpy(buf, rdata.data, rdata.length); + + if (buf[0] != 0 || + buf[2] == (DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC)) { + dns_rdata_reset(&rdata); + continue; + } + + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, origin, + 0, &rdata, &tuple)); + CHECK(do_one_tuple(&tuple, db, ver, diff)); + INSIST(tuple == NULL); + + rdata.data = buf; + buf[2] = DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC; + + CHECK(rr_exists(db, ver, origin, &rdata, &flag)); + + if (!flag) { + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, + origin, 0, &rdata, &tuple)); + CHECK(do_one_tuple(&tuple, db, ver, diff)); + INSIST(tuple == NULL); + } + dns_rdata_reset(&rdata); + } + if (result != ISC_R_NOMORE) + goto failure; + success: + result = ISC_R_SUCCESS; + + failure: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + dns_db_detachnode(db, &node); + return (result); +} +#endif + +isc_result_t +dns_nsec3_addnsec3sx(dns_db_t *db, dns_dbversion_t *version, + dns_name_t *name, dns_ttl_t nsecttl, + isc_boolean_t unsecure, dns_rdatatype_t type, + dns_diff_t *diff) +{ + dns_dbnode_t *node = NULL; + dns_rdata_nsec3param_t nsec3param; + dns_rdataset_t rdataset; + dns_rdataset_t prdataset; + isc_result_t result; + + dns_rdataset_init(&rdataset); + dns_rdataset_init(&prdataset); + + /* + * Find the NSEC3 parameters for this zone. + */ + result = dns_db_getoriginnode(db, &node); + if (result != ISC_R_SUCCESS) + return (result); + + result = dns_db_findrdataset(db, node, version, type, 0, 0, + &prdataset, NULL); + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) + goto failure; + + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec3param, 0, 0, + &rdataset, NULL); + if (result == ISC_R_NOTFOUND) + goto try_private; + if (result != ISC_R_SUCCESS) + goto failure; + + /* + * Update each active NSEC3 chain. + */ + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(&rdataset, &rdata); + CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); -#ifdef RFC5155_STRICT if (nsec3param.flags != 0) continue; -#else + + /* + * We have a active chain. Update it. + */ + CHECK(dns_nsec3_addnsec3(db, version, name, &nsec3param, + nsecttl, unsecure, diff)); + } + if (result != ISC_R_NOMORE) + goto failure; + + dns_rdataset_disassociate(&rdataset); + + try_private: + if (!dns_rdataset_isassociated(&prdataset)) + goto success; + /* + * Update each active NSEC3 chain. + */ + for (result = dns_rdataset_first(&prdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&prdataset)) { + dns_rdata_t rdata1 = DNS_RDATA_INIT; + dns_rdata_t rdata2 = DNS_RDATA_INIT; + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + + dns_rdataset_current(&prdataset, &rdata1); + if (!dns_nsec3param_fromprivate(&rdata1, &rdata2, + buf, sizeof(buf))) + continue; + CHECK(dns_rdata_tostruct(&rdata2, &nsec3param, NULL)); + if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) continue; - if (better_param(&rdataset, &rdata)) + if (better_param(&prdataset, &rdata2)) continue; -#endif /* * We have a active chain. Update it. @@ -947,11 +1260,13 @@ dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version, nsecttl, unsecure, diff)); } if (result == ISC_R_NOMORE) + success: result = ISC_R_SUCCESS; - failure: if (dns_rdataset_isassociated(&rdataset)) dns_rdataset_disassociate(&rdataset); + if (dns_rdataset_isassociated(&prdataset)) + dns_rdataset_disassociate(&prdataset); if (node != NULL) dns_db_detachnode(db, &node); @@ -1120,6 +1435,8 @@ dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, */ nsec3.next = nexthash; nsec3.next_length = next_length; + if (CREATE(nsec3param->flags)) + nsec3.flags = nsec3param->flags & DNS_NSEC3FLAG_OPTOUT; isc_buffer_init(&buffer, nsec3buf, sizeof(nsec3buf)); CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass, dns_rdatatype_nsec3, &nsec3, @@ -1257,6 +1574,13 @@ isc_result_t dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, dns_diff_t *diff) { + return (dns_nsec3_delnsec3sx(db, version, name, 0, diff)); +} + +isc_result_t +dns_nsec3_delnsec3sx(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, + dns_rdatatype_t privatetype, dns_diff_t *diff) +{ dns_dbnode_t *node = NULL; dns_rdata_nsec3param_t nsec3param; dns_rdataset_t rdataset; @@ -1274,11 +1598,10 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, result = dns_db_findrdataset(db, node, version, dns_rdatatype_nsec3param, 0, 0, &rdataset, NULL); - dns_db_detachnode(db, &node); if (result == ISC_R_NOTFOUND) - return (ISC_R_SUCCESS); + goto try_private; if (result != ISC_R_SUCCESS) - return (result); + goto failure; /* * Update each active NSEC3 chain. @@ -1289,17 +1612,47 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_current(&rdataset, &rdata); - dns_rdata_tostruct(&rdata, &nsec3param, NULL); + CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); -#ifdef RFC5155_STRICT if (nsec3param.flags != 0) continue; -#else + /* + * We have a active chain. Update it. + */ + CHECK(dns_nsec3_delnsec3(db, version, name, &nsec3param, diff)); + } + dns_rdataset_disassociate(&rdataset); + + try_private: + if (privatetype == 0) + goto success; + result = dns_db_findrdataset(db, node, version, privatetype, 0, 0, + &rdataset, NULL); + if (result == ISC_R_NOTFOUND) + goto success; + if (result != ISC_R_SUCCESS) + goto failure; + + /* + * Update each NSEC3 chain being built. + */ + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata1 = DNS_RDATA_INIT; + dns_rdata_t rdata2 = DNS_RDATA_INIT; + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + + dns_rdataset_current(&rdataset, &rdata1); + if (!dns_nsec3param_fromprivate(&rdata1, &rdata2, + buf, sizeof(buf))) + continue; + CHECK(dns_rdata_tostruct(&rdata2, &nsec3param, NULL)); + if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) continue; - if (better_param(&rdataset, &rdata)) + if (better_param(&rdataset, &rdata2)) continue; -#endif /* * We have a active chain. Update it. @@ -1307,6 +1660,7 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, CHECK(dns_nsec3_delnsec3(db, version, name, &nsec3param, diff)); } if (result == ISC_R_NOMORE) + success: result = ISC_R_SUCCESS; failure: @@ -1322,6 +1676,14 @@ isc_result_t dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version, isc_boolean_t complete, isc_boolean_t *answer) { + return (dns_nsec3_activex(db, version, complete, 0, answer)); +} + +isc_result_t +dns_nsec3_activex(dns_db_t *db, dns_dbversion_t *version, + isc_boolean_t complete, dns_rdatatype_t privatetype, + isc_boolean_t *answer) +{ dns_dbnode_t *node = NULL; dns_rdataset_t rdataset; dns_rdata_nsec3param_t nsec3param; @@ -1338,34 +1700,78 @@ dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version, result = dns_db_findrdataset(db, node, version, dns_rdatatype_nsec3param, 0, 0, &rdataset, NULL); - dns_db_detachnode(db, &node); + if (result == ISC_R_NOTFOUND) + goto try_private; + + if (result != ISC_R_SUCCESS) { + dns_db_detachnode(db, &node); + return (result); + } + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + if (nsec3param.flags == 0) + break; + } + dns_rdataset_disassociate(&rdataset); + if (result == ISC_R_SUCCESS) { + dns_db_detachnode(db, &node); + *answer = ISC_TRUE; + return (ISC_R_SUCCESS); + } + if (result == ISC_R_NOMORE) + *answer = ISC_FALSE; + + try_private: + if (privatetype == 0 || complete) { + *answer = ISC_FALSE; + return (ISC_R_SUCCESS); + } + result = dns_db_findrdataset(db, node, version, privatetype, 0, 0, + &rdataset, NULL); + + dns_db_detachnode(db, &node); if (result == ISC_R_NOTFOUND) { *answer = ISC_FALSE; return (ISC_R_SUCCESS); } if (result != ISC_R_SUCCESS) return (result); + for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(&rdataset)) { - dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_t rdata1 = DNS_RDATA_INIT; + dns_rdata_t rdata2 = DNS_RDATA_INIT; + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; - dns_rdataset_current(&rdataset, &rdata); - result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); + dns_rdataset_current(&rdataset, &rdata1); + if (!dns_nsec3param_fromprivate(&rdata1, &rdata2, + buf, sizeof(buf))) + continue; + result = dns_rdata_tostruct(&rdata2, &nsec3param, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); - if ((nsec3param.flags) == 0 || - (!complete && CREATE(nsec3param.flags))) + if (!complete && CREATE(nsec3param.flags)) break; } dns_rdataset_disassociate(&rdataset); - if (result == ISC_R_SUCCESS) + if (result == ISC_R_SUCCESS) { *answer = ISC_TRUE; + result = ISC_R_SUCCESS; + } if (result == ISC_R_NOMORE) { *answer = ISC_FALSE; result = ISC_R_SUCCESS; } + return (result); } diff --git a/lib/dns/openssl_link.c b/lib/dns/openssl_link.c index 081e3c6..8c733f6 100644 --- a/lib/dns/openssl_link.c +++ b/lib/dns/openssl_link.c @@ -31,7 +31,7 @@ /* * Principal Author: Brian Wellington - * $Id: openssl_link.c,v 1.22.112.5 2010-09-15 12:37:35 tbox Exp $ + * $Id: openssl_link.c,v 1.29 2010-09-15 12:38:36 tbox Exp $ */ #ifdef OPENSSL @@ -45,6 +45,8 @@ #include #include +#include + #include "dst_internal.h" #include "dst_openssl.h" @@ -60,12 +62,6 @@ #ifdef USE_ENGINE #include - -#ifdef ENGINE_ID -const char *engine_id = ENGINE_ID; -#else -const char *engine_id; -#endif #endif static RAND_METHOD *rm = NULL; @@ -74,15 +70,7 @@ static isc_mutex_t *locks = NULL; static int nlocks; #ifdef USE_ENGINE -static ENGINE *e; -static ENGINE *he; -#endif - -#ifdef USE_PKCS11 -static isc_result_t -dst__openssl_load_engine(const char *name, const char *engine_id, - const char **pre_cmds, int pre_num, - const char **post_cmds, int post_num); +static ENGINE *e = NULL; #endif static int @@ -135,8 +123,16 @@ id_callback(void) { static void * mem_alloc(size_t size) { +#ifdef OPENSSL_LEAKS + void *ptr; + + INSIST(dst__memory_pool != NULL); + ptr = isc_mem_allocate(dst__memory_pool, size); + return (ptr); +#else INSIST(dst__memory_pool != NULL); return (isc_mem_allocate(dst__memory_pool, size)); +#endif } static void @@ -148,16 +144,26 @@ mem_free(void *ptr) { static void * mem_realloc(void *ptr, size_t size) { +#ifdef OPENSSL_LEAKS + void *rptr; + + INSIST(dst__memory_pool != NULL); + rptr = isc_mem_reallocate(dst__memory_pool, ptr, size); + return (rptr); +#else INSIST(dst__memory_pool != NULL); return (isc_mem_reallocate(dst__memory_pool, ptr, size)); +#endif } isc_result_t -dst__openssl_init() { +dst__openssl_init(const char *engine) { isc_result_t result; #ifdef USE_ENGINE - /* const char *name; */ ENGINE *re; +#else + + UNUSED(engine); #endif #ifdef DNS_CRYPTO_LEAKS @@ -187,70 +193,26 @@ dst__openssl_init() { rm->add = entropy_add; rm->pseudorand = entropy_getpseudo; rm->status = entropy_status; + #ifdef USE_ENGINE OPENSSL_config(NULL); -#ifdef USE_PKCS11 -#ifndef PKCS11_SO_PATH -#define PKCS11_SO_PATH "/usr/local/lib/engines/engine_pkcs11.so" -#endif -#ifndef PKCS11_MODULE_PATH -#define PKCS11_MODULE_PATH "/usr/lib/libpkcs11.so" -#endif - { - /* - * to use this to config the PIN, add in openssl.cnf: - * - at the beginning: "openssl_conf = openssl_def" - * - at any place these sections: - * [ openssl_def ] - * engines = engine_section - * [ engine_section ] - * pkcs11 = pkcs11_section - * [ pkcs11_section ] - * PIN = my___pin - */ - - const char *pre_cmds[] = { - "SO_PATH", PKCS11_SO_PATH, - "LOAD", NULL, - "MODULE_PATH", PKCS11_MODULE_PATH - }; - const char *post_cmds[] = { - /* "PIN", "my___pin" */ - }; - result = dst__openssl_load_engine("pkcs11", "pkcs11", - pre_cmds, 0, - post_cmds, /*1*/ 0); - if (result != ISC_R_SUCCESS) - goto cleanup_rm; - } -#endif /* USE_PKCS11 */ - if (engine_id != NULL) { - e = ENGINE_by_id(engine_id); + + if (engine != NULL && *engine == '\0') + engine = NULL; + + if (engine != NULL) { + e = ENGINE_by_id(engine); if (e == NULL) { - result = ISC_R_NOTFOUND; + result = DST_R_NOENGINE; goto cleanup_rm; } - if (!ENGINE_init(e)) { - result = ISC_R_FAILURE; - ENGINE_free(e); + /* This will init the engine. */ + if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { + result = DST_R_NOENGINE; goto cleanup_rm; } - ENGINE_set_default(e, ENGINE_METHOD_ALL); - ENGINE_free(e); - } else { - ENGINE_register_all_complete(); - for (e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e)) { - - /* - * Something weird here. If we call ENGINE_finish() - * ENGINE_get_default_RAND() will fail. - */ - if (ENGINE_init(e)) { - if (he == NULL) - he = e; - } - } } + re = ENGINE_get_default_RAND(); if (re == NULL) { re = ENGINE_new(); @@ -263,7 +225,6 @@ dst__openssl_init() { ENGINE_free(re); } else ENGINE_finish(re); - #else RAND_set_rand_method(rm); #endif /* USE_ENGINE */ @@ -271,13 +232,18 @@ dst__openssl_init() { #ifdef USE_ENGINE cleanup_rm: + if (e != NULL) + ENGINE_free(e); + e = NULL; mem_free(rm); + rm = NULL; #endif cleanup_mutexinit: CRYPTO_set_locking_callback(NULL); DESTROYMUTEXBLOCK(locks, nlocks); cleanup_mutexalloc: mem_free(locks); + locks = NULL; return (result); } @@ -287,15 +253,22 @@ dst__openssl_destroy() { /* * Sequence taken from apps_shutdown() in . */ + if (rm != NULL) { +#if OPENSSL_VERSION_NUMBER >= 0x00907000L + RAND_cleanup(); +#endif + mem_free(rm); + rm = NULL; + } #if (OPENSSL_VERSION_NUMBER >= 0x00907000L) - CONF_modules_unload(1); + CONF_modules_free(); #endif + OBJ_cleanup(); EVP_cleanup(); #if defined(USE_ENGINE) - if (e != NULL) { - ENGINE_finish(e); - e = NULL; - } + if (e != NULL) + ENGINE_free(e); + e = NULL; #if defined(USE_ENGINE) && OPENSSL_VERSION_NUMBER >= 0x00907000L ENGINE_cleanup(); #endif @@ -304,23 +277,18 @@ dst__openssl_destroy() { CRYPTO_cleanup_all_ex_data(); #endif ERR_clear_error(); - ERR_free_strings(); ERR_remove_state(0); + ERR_free_strings(); #ifdef DNS_CRYPTO_LEAKS CRYPTO_mem_leaks_fp(stderr); #endif - if (rm != NULL) { -#if OPENSSL_VERSION_NUMBER >= 0x00907000L - RAND_cleanup(); -#endif - mem_free(rm); - } if (locks != NULL) { CRYPTO_set_locking_callback(NULL); DESTROYMUTEXBLOCK(locks, nlocks); mem_free(locks); + locks = NULL; } } @@ -341,91 +309,18 @@ dst__openssl_toresult(isc_result_t fallback) { } ENGINE * -dst__openssl_getengine(const char *name) { - - UNUSED(name); - +dst__openssl_getengine(const char *engine) { + if (engine == NULL) + return (NULL); #if defined(USE_ENGINE) - return (he); -#else - return (NULL); -#endif -} - -isc_result_t -dst__openssl_setdefault(const char *name) { - - UNUSED(name); - -#if defined(USE_ENGINE) - ENGINE_set_default(e, ENGINE_METHOD_ALL); -#endif - /* - * XXXMPA If the engine does not have a default RAND method - * restore our method. - */ - return (ISC_R_SUCCESS); -} - -#ifdef USE_PKCS11 -/* - * 'name' is the name the engine is known by to the dst library. - * This may or may not match the name the engine is known by to - * openssl. It is the name that is stored in the private key file. - * - * 'engine_id' is the openssl engine name. - * - * pre_cmds and post_cmds a sequence if command argument pairs - * pre_num and post_num are a count of those pairs. - * - * "SO_PATH", PKCS11_SO_PATH ("/usr/local/lib/engines/engine_pkcs11.so") - * "LOAD", NULL - * "MODULE_PATH", PKCS11_MODULE_PATH ("/usr/lib/libpkcs11.so") - */ -static isc_result_t -dst__openssl_load_engine(const char *name, const char *engine_id, - const char **pre_cmds, int pre_num, - const char **post_cmds, int post_num) -{ - ENGINE *e; - - UNUSED(name); - - if (!strcasecmp(engine_id, "dynamic")) - ENGINE_load_dynamic(); - e = ENGINE_by_id(engine_id); if (e == NULL) - return (ISC_R_NOTFOUND); - while (pre_num--) { - if (!ENGINE_ctrl_cmd_string(e, pre_cmds[0], pre_cmds[1], 0)) { - ENGINE_free(e); - return (ISC_R_FAILURE); - } - pre_cmds += 2; - } - if (!ENGINE_init(e)) { - ENGINE_free(e); - return (ISC_R_FAILURE); - } - /* - * ENGINE_init() returned a functional reference, so free the - * structural reference from ENGINE_by_id(). - */ - ENGINE_free(e); - while (post_num--) { - if (!ENGINE_ctrl_cmd_string(e, post_cmds[0], post_cmds[1], 0)) { - ENGINE_free(e); - return (ISC_R_FAILURE); - } - post_cmds += 2; - } - if (he != NULL) - ENGINE_finish(he); - he = e; - return (ISC_R_SUCCESS); + return (NULL); + if (strcmp(engine, ENGINE_get_id(e)) == 0) + return (e); +#endif + return (NULL); } -#endif /* USE_PKCS11 */ #else /* OPENSSL */ diff --git a/lib/dns/openssldh_link.c b/lib/dns/openssldh_link.c index e31137f..9deda6b 100644 --- a/lib/dns/openssldh_link.c +++ b/lib/dns/openssldh_link.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -31,7 +31,7 @@ /* * Principal Author: Brian Wellington - * $Id: openssldh_link.c,v 1.14 2008-04-01 23:47:10 tbox Exp $ + * $Id: openssldh_link.c,v 1.20 2011-01-11 23:47:13 tbox Exp $ */ #ifdef OPENSSL @@ -149,12 +149,37 @@ openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { return (ISC_TRUE); } +#if OPENSSL_VERSION_NUMBER > 0x00908000L +static int +progress_cb(int p, int n, BN_GENCB *cb) +{ + union { + void *dptr; + void (*fptr)(int); + } u; + + UNUSED(n); + + u.dptr = cb->arg; + if (u.fptr != NULL) + u.fptr(p); + return (1); +} +#endif + static isc_result_t -openssldh_generate(dst_key_t *key, int generator) { +openssldh_generate(dst_key_t *key, int generator, void (*callback)(int)) { + DH *dh = NULL; #if OPENSSL_VERSION_NUMBER > 0x00908000L BN_GENCB cb; + union { + void *dptr; + void (*fptr)(int); + } u; +#else + + UNUSED(callback); #endif - DH *dh = NULL; if (generator == 0) { if (key->key_size == 768 || @@ -181,7 +206,12 @@ openssldh_generate(dst_key_t *key, int generator) { if (dh == NULL) return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - BN_GENCB_set_old(&cb, NULL, NULL); + if (callback == NULL) { + BN_GENCB_set_old(&cb, NULL, NULL); + } else { + u.fptr = callback; + BN_GENCB_set(&cb, &progress_cb, u.dptr); + } if (!DH_generate_parameters_ex(dh, key->key_size, generator, &cb)) { @@ -476,7 +506,7 @@ openssldh_tofile(const dst_key_t *key, const char *directory) { } static isc_result_t -openssldh_parse(dst_key_t *key, isc_lex_t *lexer) { +openssldh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t ret; int i; @@ -484,6 +514,7 @@ openssldh_parse(dst_key_t *key, isc_lex_t *lexer) { isc_mem_t *mctx; #define DST_RET(a) {ret = a; goto err;} + UNUSED(pub); mctx = key->mctx; /* read private key file */ @@ -609,6 +640,8 @@ static dst_func_t openssldh_functions = { openssldh_parse, openssldh_cleanup, NULL, /*%< fromlabel */ + NULL, /*%< dump */ + NULL, /*%< restore */ }; isc_result_t diff --git a/lib/dns/openssldsa_link.c b/lib/dns/openssldsa_link.c index c563d9b..ae88d4c 100644 --- a/lib/dns/openssldsa_link.c +++ b/lib/dns/openssldsa_link.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -29,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: openssldsa_link.c,v 1.13.120.2 2009-01-14 23:47:26 tbox Exp $ */ +/* $Id: openssldsa_link.c,v 1.20 2011-01-11 23:47:13 tbox Exp $ */ #ifdef OPENSSL #ifndef USE_EVP @@ -313,15 +313,40 @@ openssldsa_compare(const dst_key_t *key1, const dst_key_t *key2) { return (ISC_TRUE); } -static isc_result_t -openssldsa_generate(dst_key_t *key, int unused) { #if OPENSSL_VERSION_NUMBER > 0x00908000L - BN_GENCB cb; +static int +progress_cb(int p, int n, BN_GENCB *cb) +{ + union { + void *dptr; + void (*fptr)(int); + } u; + + UNUSED(n); + + u.dptr = cb->arg; + if (u.fptr != NULL) + u.fptr(p); + return (1); +} #endif + +static isc_result_t +openssldsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { DSA *dsa; unsigned char rand_array[ISC_SHA1_DIGESTLENGTH]; isc_result_t result; +#if OPENSSL_VERSION_NUMBER > 0x00908000L + BN_GENCB cb; + union { + void *dptr; + void (*fptr)(int); + } u; + +#else + UNUSED(callback); +#endif UNUSED(unused); result = dst__entropy_getdata(rand_array, sizeof(rand_array), @@ -334,7 +359,12 @@ openssldsa_generate(dst_key_t *key, int unused) { if (dsa == NULL) return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); - BN_GENCB_set_old(&cb, NULL, NULL); + if (callback == NULL) { + BN_GENCB_set_old(&cb, NULL, NULL); + } else { + u.fptr = callback; + BN_GENCB_set(&cb, &progress_cb, u.dptr); + } if (!DSA_generate_parameters_ex(dsa, key->key_size, rand_array, ISC_SHA1_DIGESTLENGTH, NULL, NULL, @@ -512,7 +542,7 @@ openssldsa_tofile(const dst_key_t *key, const char *directory) { } static isc_result_t -openssldsa_parse(dst_key_t *key, isc_lex_t *lexer) { +openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t ret; int i; @@ -520,6 +550,7 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer) { isc_mem_t *mctx = key->mctx; #define DST_RET(a) {ret = a; goto err;} + UNUSED(pub); /* read private key file */ ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv); if (ret != ISC_R_SUCCESS) @@ -587,6 +618,8 @@ static dst_func_t openssldsa_functions = { openssldsa_parse, NULL, /*%< cleanup */ NULL, /*%< fromlabel */ + NULL, /*%< dump */ + NULL, /*%< restore */ }; isc_result_t diff --git a/lib/dns/opensslgost_link.c b/lib/dns/opensslgost_link.c new file mode 100644 index 0000000..1b029db --- /dev/null +++ b/lib/dns/opensslgost_link.c @@ -0,0 +1,418 @@ +/* + * Copyright (C) 2010, 2011 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: opensslgost_link.c,v 1.5 2011-01-19 23:47:12 tbox Exp $ */ + +#include + +#ifdef HAVE_OPENSSL_GOST + +#include +#include +#include +#include + +#include + +#include "dst_internal.h" +#include "dst_openssl.h" +#include "dst_parse.h" + +#include +#include +#include +#include + +static ENGINE *e = NULL; +static const EVP_MD *opensslgost_digest; +extern const EVP_MD *EVP_gost(void); + +const EVP_MD *EVP_gost(void) { + return (opensslgost_digest); +} + +#define DST_RET(a) {ret = a; goto err;} + +static isc_result_t opensslgost_todns(const dst_key_t *key, + isc_buffer_t *data); + +static isc_result_t +opensslgost_createctx(dst_key_t *key, dst_context_t *dctx) { + EVP_MD_CTX *evp_md_ctx; + const EVP_MD *md = EVP_gost(); + + UNUSED(key); + + if (md == NULL) + return (DST_R_OPENSSLFAILURE); + + evp_md_ctx = EVP_MD_CTX_create(); + if (evp_md_ctx == NULL) + return (ISC_R_NOMEMORY); + + if (!EVP_DigestInit_ex(evp_md_ctx, md, NULL)) { + EVP_MD_CTX_destroy(evp_md_ctx); + return (ISC_R_FAILURE); + } + dctx->ctxdata.evp_md_ctx = evp_md_ctx; + + return (ISC_R_SUCCESS); +} + +static void +opensslgost_destroyctx(dst_context_t *dctx) { + EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; + + if (evp_md_ctx != NULL) { + EVP_MD_CTX_destroy(evp_md_ctx); + dctx->ctxdata.evp_md_ctx = NULL; + } +} + +static isc_result_t +opensslgost_adddata(dst_context_t *dctx, const isc_region_t *data) { + EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; + + if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length)) + return (ISC_R_FAILURE); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +opensslgost_sign(dst_context_t *dctx, isc_buffer_t *sig) { + dst_key_t *key = dctx->key; + isc_region_t r; + unsigned int siglen = 0; + EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; + EVP_PKEY *pkey = key->keydata.pkey; + + isc_buffer_availableregion(sig, &r); + + if (r.length < (unsigned int) EVP_PKEY_size(pkey)) + return (ISC_R_NOSPACE); + + if (!EVP_SignFinal(evp_md_ctx, r.base, &siglen, pkey)) + return (ISC_R_FAILURE); + + isc_buffer_add(sig, siglen); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +opensslgost_verify(dst_context_t *dctx, const isc_region_t *sig) { + dst_key_t *key = dctx->key; + int status = 0; + EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; + EVP_PKEY *pkey = key->keydata.pkey; + + status = EVP_VerifyFinal(evp_md_ctx, sig->base, sig->length, pkey); + if (status != 1) + return (dst__openssl_toresult(DST_R_VERIFYFAILURE)); + + return (ISC_R_SUCCESS); +} + +static isc_boolean_t +opensslgost_compare(const dst_key_t *key1, const dst_key_t *key2) { + EVP_PKEY *pkey1, *pkey2; + + pkey1 = key1->keydata.pkey; + pkey2 = key2->keydata.pkey; + + if (pkey1 == NULL && pkey2 == NULL) + return (ISC_TRUE); + else if (pkey1 == NULL || pkey2 == NULL) + return (ISC_FALSE); + + if (EVP_PKEY_cmp(pkey1, pkey2) != 1) + return (ISC_FALSE); + return (ISC_TRUE); +} + +static int +progress_cb(EVP_PKEY_CTX *ctx) +{ + union { + void *dptr; + void (*fptr)(int); + } u; + int p; + + u.dptr = EVP_PKEY_CTX_get_app_data(ctx); + p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); + if (u.fptr != NULL) + u.fptr(p); + return (1); +} + +static isc_result_t +opensslgost_generate(dst_key_t *key, int unused, void (*callback)(int)) { + EVP_PKEY_CTX *ctx; + union { + void *dptr; + void (*fptr)(int); + } u; + EVP_PKEY *pkey = NULL; + + UNUSED(unused); + ctx = EVP_PKEY_CTX_new_id(NID_id_GostR3410_2001, NULL); + if (ctx == NULL) + goto err; + if (callback != NULL) { + u.fptr = callback; + EVP_PKEY_CTX_set_app_data(ctx, u.dptr); + EVP_PKEY_CTX_set_cb(ctx, &progress_cb); + } + if (EVP_PKEY_keygen_init(ctx) <= 0) + goto err; + if (EVP_PKEY_CTX_ctrl_str(ctx, "paramset", "A") <= 0) + goto err; + if (EVP_PKEY_keygen(ctx, &pkey) <= 0) + goto err; + key->keydata.pkey = pkey; + EVP_PKEY_CTX_free(ctx); + return (ISC_R_SUCCESS); + +err: + if (pkey != NULL) + EVP_PKEY_free(pkey); + if (ctx != NULL) + EVP_PKEY_CTX_free(ctx); + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); +} + +static isc_boolean_t +opensslgost_isprivate(const dst_key_t *key) { + EVP_PKEY *pkey = key->keydata.pkey; + EC_KEY *ec; + + INSIST(pkey != NULL); + + ec = EVP_PKEY_get0(pkey); + return (ISC_TF(ec != NULL && EC_KEY_get0_private_key(ec) != NULL)); +} + +static void +opensslgost_destroy(dst_key_t *key) { + EVP_PKEY *pkey = key->keydata.pkey; + + EVP_PKEY_free(pkey); + key->keydata.pkey = NULL; +} + +unsigned char gost_prefix[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 +}; + +static isc_result_t +opensslgost_todns(const dst_key_t *key, isc_buffer_t *data) { + EVP_PKEY *pkey; + isc_region_t r; + unsigned char der[37 + 64], *p; + int len; + + REQUIRE(key->keydata.pkey != NULL); + + pkey = key->keydata.pkey; + + isc_buffer_availableregion(data, &r); + if (r.length < 64) + return (ISC_R_NOSPACE); + + p = der; + len = i2d_PUBKEY(pkey, &p); + INSIST(len == sizeof(der)); + INSIST(memcmp(gost_prefix, der, 37) == 0); + memcpy(r.base, der + 37, 64); + isc_buffer_add(data, 64); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) { + isc_region_t r; + EVP_PKEY *pkey = NULL; + unsigned char der[37 + 64]; + const unsigned char *p; + + isc_buffer_remainingregion(data, &r); + if (r.length == 0) + return (ISC_R_SUCCESS); + + if (r.length != 64) + return (DST_R_INVALIDPUBLICKEY); + memcpy(der, gost_prefix, 37); + memcpy(der + 37, r.base, 64); + isc_buffer_forward(data, 64); + + p = der; + if (d2i_PUBKEY(&pkey, &p, (long) sizeof(der)) == NULL) + return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + key->keydata.pkey = pkey; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +opensslgost_tofile(const dst_key_t *key, const char *directory) { + EVP_PKEY *pkey; + dst_private_t priv; + isc_result_t result; + unsigned char *der, *p; + int len; + + if (key->keydata.pkey == NULL) + return (DST_R_NULLKEY); + + pkey = key->keydata.pkey; + + len = i2d_PrivateKey(pkey, NULL); + der = isc_mem_get(key->mctx, (size_t) len); + if (der == NULL) + return (ISC_R_NOMEMORY); + + p = der; + if (i2d_PrivateKey(pkey, &p) != len) { + result = dst__openssl_toresult(DST_R_OPENSSLFAILURE); + goto fail; + } + + priv.elements[0].tag = TAG_GOST_PRIVASN1; + priv.elements[0].length = len; + priv.elements[0].data = der; + priv.nelements = GOST_NTAGS; + + result = dst__privstruct_writefile(key, &priv, directory); + fail: + if (der != NULL) + isc_mem_put(key->mctx, der, (size_t) len); + return (result); +} + +static isc_result_t +opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + dst_private_t priv; + isc_result_t ret; + isc_mem_t *mctx = key->mctx; + EVP_PKEY *pkey = NULL; + const unsigned char *p; + + UNUSED(pub); + + /* read private key file */ + ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv); + if (ret != ISC_R_SUCCESS) + return (ret); + + INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1); + p = priv.elements[0].data; + if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p, + (long) priv.elements[0].length) == NULL) + DST_RET(DST_R_INVALIDPRIVATEKEY); + key->keydata.pkey = pkey; + key->key_size = EVP_PKEY_bits(pkey); + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (ISC_R_SUCCESS); + + err: + if (pkey != NULL) + EVP_PKEY_free(pkey); + opensslgost_destroy(key); + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (ret); +} + +static void +opensslgost_cleanup(void) { + if (e != NULL) { + ENGINE_finish(e); + ENGINE_free(e); + e = NULL; + } +} + +static dst_func_t opensslgost_functions = { + opensslgost_createctx, + opensslgost_destroyctx, + opensslgost_adddata, + opensslgost_sign, + opensslgost_verify, + NULL, /*%< computesecret */ + opensslgost_compare, + NULL, /*%< paramcompare */ + opensslgost_generate, + opensslgost_isprivate, + opensslgost_destroy, + opensslgost_todns, + opensslgost_fromdns, + opensslgost_tofile, + opensslgost_parse, + opensslgost_cleanup, + NULL, /*%< fromlabel */ + NULL, /*%< dump */ + NULL /*%< restore */ +}; + +isc_result_t +dst__opensslgost_init(dst_func_t **funcp) { + REQUIRE(funcp != NULL); + + /* check if the gost engine works properly */ + e = ENGINE_by_id("gost"); + if (e == NULL) + return (DST_R_OPENSSLFAILURE); + if (ENGINE_init(e) <= 0) { + ENGINE_free(e); + e = NULL; + return (DST_R_OPENSSLFAILURE); + } + /* better than to rely on digest_gost symbol */ + opensslgost_digest = ENGINE_get_digest(e, NID_id_GostR3411_94); + /* from openssl.cnf */ + if ((opensslgost_digest == NULL) || + (ENGINE_register_pkey_asn1_meths(e) <= 0) || + (ENGINE_ctrl_cmd_string(e, + "CRYPT_PARAMS", + "id-Gost28147-89-CryptoPro-A-ParamSet", + 0) <= 0)) { + ENGINE_finish(e); + ENGINE_free(e); + e = NULL; + return (DST_R_OPENSSLFAILURE); + } + + if (*funcp == NULL) + *funcp = &opensslgost_functions; + return (ISC_R_SUCCESS); +} + +#else /* HAVE_OPENSSL_GOST */ + +#include + +EMPTY_TRANSLATION_UNIT + +#endif /* HAVE_OPENSSL_GOST */ +/*! \file */ diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c index 1e3c5c2..fcdc9f0 100644 --- a/lib/dns/opensslrsa_link.c +++ b/lib/dns/opensslrsa_link.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -17,7 +17,7 @@ /* * Principal Author: Brian Wellington - * $Id: opensslrsa_link.c,v 1.20.50.8 2010-01-22 02:36:49 marka Exp $ + * $Id: opensslrsa_link.c,v 1.39 2011-01-11 23:47:13 tbox Exp $ */ #ifdef OPENSSL #include @@ -30,6 +30,7 @@ #endif #endif + #include #include #include @@ -368,7 +369,7 @@ opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { RSA *rsa = key->keydata.rsa; /* note: ISC_SHA512_DIGESTLENGTH >= ISC_*_DIGESTLENGTH */ unsigned char digest[PREFIXLEN + ISC_SHA512_DIGESTLENGTH]; - int status = 0; + int status; int type = 0; unsigned int digestlen = 0; char *message; @@ -703,10 +704,32 @@ opensslrsa_compare(const dst_key_t *key1, const dst_key_t *key2) { return (ISC_TRUE); } +#if OPENSSL_VERSION_NUMBER > 0x00908000L +static int +progress_cb(int p, int n, BN_GENCB *cb) +{ + union { + void *dptr; + void (*fptr)(int); + } u; + + UNUSED(n); + + u.dptr = cb->arg; + if (u.fptr != NULL) + u.fptr(p); + return (1); +} +#endif + static isc_result_t -opensslrsa_generate(dst_key_t *key, int exp) { +opensslrsa_generate(dst_key_t *key, int exp, void (*callback)(int)) { #if OPENSSL_VERSION_NUMBER > 0x00908000L BN_GENCB cb; + union { + void *dptr; + void (*fptr)(int); + } u; RSA *rsa = RSA_new(); BIGNUM *e = BN_new(); #if USE_EVP @@ -732,7 +755,12 @@ opensslrsa_generate(dst_key_t *key, int exp) { BN_set_bit(e, 32); } - BN_GENCB_set_old(&cb, NULL, NULL); + if (callback == NULL) { + BN_GENCB_set_old(&cb, NULL, NULL); + } else { + u.fptr = callback; + BN_GENCB_set(&cb, &progress_cb, u.dptr); + } if (RSA_generate_key_ex(rsa, key->key_size, e, &cb)) { BN_free(e); @@ -763,8 +791,12 @@ err: #if USE_EVP EVP_PKEY *pkey = EVP_PKEY_new(); + UNUSED(callback); + if (pkey == NULL) return (ISC_R_NOMEMORY); +#else + UNUSED(callback); #endif if (exp == 0) @@ -1059,8 +1091,9 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) { i++; } + priv.nelements = i; - result = dst__privstruct_writefile(key, &priv, directory); + result = dst__privstruct_writefile(key, &priv, directory); fail: #if USE_EVP RSA_free(rsa); @@ -1074,16 +1107,52 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) { } static isc_result_t -opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer) { +rsa_check(RSA *rsa, RSA *pub) +{ + /* Public parameters should be the same but if they are not set + * copy them from the public key. */ + if (pub != NULL) { + if (rsa->n != NULL) { + if (BN_cmp(rsa->n, pub->n) != 0) + return (DST_R_INVALIDPRIVATEKEY); + } else { + rsa->n = pub->n; + pub->n = NULL; + } + if (rsa->e != NULL) { + if (BN_cmp(rsa->e, pub->e) != 0) + return (DST_R_INVALIDPRIVATEKEY); + } else { + rsa->e = pub->e; + pub->e = NULL; + } + } + if (rsa->n == NULL || rsa->e == NULL) + return (DST_R_INVALIDPRIVATEKEY); + return (ISC_R_SUCCESS); +} + +static isc_result_t +opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { dst_private_t priv; isc_result_t ret; int i; - RSA *rsa = NULL; + RSA *rsa = NULL, *pubrsa = NULL; ENGINE *e = NULL; isc_mem_t *mctx = key->mctx; - const char *name = NULL, *label = NULL; + const char *engine = NULL, *label = NULL; EVP_PKEY *pkey = NULL; +#if USE_EVP + if (pub != NULL && pub->keydata.pkey != NULL) + pubrsa = EVP_PKEY_get1_RSA(pub->keydata.pkey); +#else + if (pub != NULL && pub->keydata.rsa != NULL) { + pubrsa = pub->keydata.rsa; + pub->keydata.rsa = NULL; + } +#endif + /* read private key file */ ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv); if (ret != ISC_R_SUCCESS) @@ -1092,7 +1161,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer) { for (i = 0; i < priv.nelements; i++) { switch (priv.elements[i].tag) { case TAG_RSA_ENGINE: - name = (char *)priv.elements[i].data; + engine = (char *)priv.elements[i].data; break; case TAG_RSA_LABEL: label = (char *)priv.elements[i].data; @@ -1105,10 +1174,10 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer) { * Is this key is stored in a HSM? * See if we can fetch it. */ - if (name != NULL || label != NULL) { - INSIST(name != NULL); - INSIST(label != NULL); - e = dst__openssl_getengine(name); + if (label != NULL) { + if (engine == NULL) + DST_RET(DST_R_NOENGINE); + e = dst__openssl_getengine(engine); if (e == NULL) DST_RET(DST_R_NOENGINE); pkey = ENGINE_load_private_key(e, label, NULL, NULL); @@ -1116,22 +1185,29 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer) { /* ERR_print_errors_fp(stderr); */ DST_RET(ISC_R_NOTFOUND); } - key->engine = isc_mem_strdup(key->mctx, name); + key->engine = isc_mem_strdup(key->mctx, engine); if (key->engine == NULL) DST_RET(ISC_R_NOMEMORY); key->label = isc_mem_strdup(key->mctx, label); if (key->label == NULL) DST_RET(ISC_R_NOMEMORY); + rsa = EVP_PKEY_get1_RSA(pkey); + if (rsa == NULL) + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) + DST_RET(DST_R_INVALIDPRIVATEKEY); + if (pubrsa != NULL) + RSA_free(pubrsa); key->key_size = EVP_PKEY_bits(pkey); #if USE_EVP key->keydata.pkey = pkey; + RSA_free(rsa); #else - key->keydata.rsa = EVP_PKEY_get1_RSA(pkey); - if (rsa == NULL) - DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + key->keydata.rsa = rsa; EVP_PKEY_free(pkey); #endif dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); return (ISC_R_SUCCESS); } @@ -1144,9 +1220,8 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer) { pkey = EVP_PKEY_new(); if (pkey == NULL) DST_RET(ISC_R_NOMEMORY); - if (!EVP_PKEY_set1_RSA(pkey, rsa)) { + if (!EVP_PKEY_set1_RSA(pkey, rsa)) DST_RET(ISC_R_FAILURE); - } key->keydata.pkey = pkey; #else key->keydata.rsa = rsa; @@ -1196,8 +1271,13 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer) { } } dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) + DST_RET(DST_R_INVALIDPRIVATEKEY); key->key_size = BN_num_bits(rsa->n); + if (pubrsa != NULL) + RSA_free(pubrsa); #if USE_EVP RSA_free(rsa); #endif @@ -1211,6 +1291,8 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer) { #endif if (rsa != NULL) RSA_free(rsa); + if (pubrsa != NULL) + RSA_free(pubrsa); opensslrsa_destroy(key); dst__privstruct_free(&priv, mctx); memset(&priv, 0, sizeof(priv)); @@ -1224,33 +1306,63 @@ opensslrsa_fromlabel(dst_key_t *key, const char *engine, const char *label, ENGINE *e = NULL; isc_result_t ret; EVP_PKEY *pkey = NULL; + RSA *rsa = NULL, *pubrsa = NULL; + char *colon; UNUSED(pin); + if (engine == NULL) + DST_RET(DST_R_NOENGINE); e = dst__openssl_getengine(engine); if (e == NULL) DST_RET(DST_R_NOENGINE); + pkey = ENGINE_load_public_key(e, label, NULL, NULL); + if (pkey != NULL) { + pubrsa = EVP_PKEY_get1_RSA(pkey); + EVP_PKEY_free(pkey); + if (pubrsa == NULL) + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + } pkey = ENGINE_load_private_key(e, label, NULL, NULL); if (pkey == NULL) DST_RET(ISC_R_NOTFOUND); - key->engine = isc_mem_strdup(key->mctx, label); - if (key->engine == NULL) - DST_RET(ISC_R_NOMEMORY); + if (engine != NULL) { + key->engine = isc_mem_strdup(key->mctx, engine); + if (key->engine == NULL) + DST_RET(ISC_R_NOMEMORY); + } else { + key->engine = isc_mem_strdup(key->mctx, label); + if (key->engine == NULL) + DST_RET(ISC_R_NOMEMORY); + colon = strchr(key->engine, ':'); + if (colon != NULL) + *colon = '\0'; + } key->label = isc_mem_strdup(key->mctx, label); if (key->label == NULL) DST_RET(ISC_R_NOMEMORY); + rsa = EVP_PKEY_get1_RSA(pkey); + if (rsa == NULL) + DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); + if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) + DST_RET(DST_R_INVALIDPRIVATEKEY); + if (pubrsa != NULL) + RSA_free(pubrsa); key->key_size = EVP_PKEY_bits(pkey); #if USE_EVP key->keydata.pkey = pkey; + RSA_free(rsa); #else - key->keydata.rsa = EVP_PKEY_get1_RSA(pkey); + key->keydata.rsa = rsa; EVP_PKEY_free(pkey); - if (key->keydata.rsa == NULL) - return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); #endif return (ISC_R_SUCCESS); err: + if (rsa != NULL) + RSA_free(rsa); + if (pubrsa != NULL) + RSA_free(pubrsa); if (pkey != NULL) EVP_PKEY_free(pkey); return (ret); @@ -1274,6 +1386,8 @@ static dst_func_t opensslrsa_functions = { opensslrsa_parse, NULL, /*%< cleanup */ opensslrsa_fromlabel, + NULL, /*%< dump */ + NULL, /*%< restore */ }; isc_result_t diff --git a/lib/dns/peer.c b/lib/dns/peer.c index 1e81023..3851c3e 100644 --- a/lib/dns/peer.c +++ b/lib/dns/peer.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: peer.c,v 1.31 2008-04-03 06:09:04 tbox Exp $ */ +/* $Id: peer.c,v 1.33 2009-09-02 23:48:02 tbox Exp $ */ /*! \file */ @@ -536,7 +536,7 @@ dns_peer_setkeybycharp(dns_peer_t *peer, const char *keyval) { isc_buffer_init(&b, keyval, strlen(keyval)); isc_buffer_add(&b, strlen(keyval)); result = dns_name_fromtext(dns_fixedname_name(&fname), &b, - dns_rootname, ISC_FALSE, NULL); + dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) return (result); diff --git a/lib/dns/private.c b/lib/dns/private.c new file mode 100644 index 0000000..ba3e8ed --- /dev/null +++ b/lib/dns/private.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: private.c,v 1.3 2009-10-09 23:48:09 tbox Exp $ */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include + +/* + * We need to build the relevant chain if there exists a NSEC/NSEC3PARAM + * at the apex; normally only one or the other of NSEC/NSEC3PARAM will exist. + * + * If a NSEC3PARAM RRset exists then we will need to build a NSEC chain + * if all the NSEC3PARAM records (and associated chains) are slated for + * destruction and we have not been told to NOT build the NSEC chain. + * + * If the NSEC set exist then check to see if there is a request to create + * a NSEC3 chain. + * + * If neither NSEC/NSEC3PARAM RRsets exist at the origin and the private + * type exists then we need to examine it to determine if NSEC3 chain has + * been requested to be built otherwise a NSEC chain needs to be built. + */ + +#define REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0) +#define CREATE(x) (((x) & DNS_NSEC3FLAG_CREATE) != 0) +#define NONSEC(x) (((x) & DNS_NSEC3FLAG_NONSEC) != 0) + +#define CHECK(x) do { \ + result = (x); \ + if (result != ISC_R_SUCCESS) \ + goto failure; \ + } while (0) + +/* + * Work out if 'param' should be ignored or not (i.e. it is in the process + * of being removed). + * + * Note: we 'belt-and-braces' here by also checking for a CREATE private + * record and keep the param record in this case. + */ + +static isc_boolean_t +ignore(dns_rdata_t *param, dns_rdataset_t *privateset) { + isc_result_t result; + + for (result = dns_rdataset_first(privateset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(privateset)) { + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + dns_rdata_t private = DNS_RDATA_INIT; + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(privateset, &private); + if (!dns_nsec3param_fromprivate(&private, &rdata, + buf, sizeof(buf))) + continue; + /* + * We are going to create a new NSEC3 chain so it + * doesn't matter if we are removing this one. + */ + if (CREATE(rdata.data[1])) + return (ISC_FALSE); + if (rdata.data[0] != param->data[0] || + rdata.data[2] != param->data[2] || + rdata.data[3] != param->data[3] || + rdata.data[4] != param->data[4] || + memcmp(&rdata.data[5], ¶m->data[5], param->data[4])) + continue; + /* + * The removal of this NSEC3 chain does NOT cause a + * NSEC chain to be created so we don't need to tell + * the caller that it will be removed. + */ + if (NONSEC(rdata.data[1])) + return (ISC_FALSE); + return (ISC_TRUE); + } + return (ISC_FALSE); +} + +isc_result_t +dns_private_chains(dns_db_t *db, dns_dbversion_t *ver, + dns_rdatatype_t privatetype, + isc_boolean_t *build_nsec, isc_boolean_t *build_nsec3) +{ + dns_dbnode_t *node; + dns_rdataset_t nsecset, nsec3paramset, privateset; + isc_boolean_t nsec3chain; + isc_boolean_t signing; + isc_result_t result; + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + unsigned int count; + + node = NULL; + dns_rdataset_init(&nsecset); + dns_rdataset_init(&nsec3paramset); + dns_rdataset_init(&privateset); + + CHECK(dns_db_getoriginnode(db, &node)); + + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, + 0, (isc_stdtime_t) 0, &nsecset, NULL); + + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) + goto failure; + + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, + 0, (isc_stdtime_t) 0, &nsec3paramset, + NULL); + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) + goto failure; + + if (dns_rdataset_isassociated(&nsecset) && + dns_rdataset_isassociated(&nsec3paramset)) { + if (build_nsec != NULL) + *build_nsec = ISC_TRUE; + if (build_nsec3 != NULL) + *build_nsec3 = ISC_TRUE; + goto success; + } + + if (privatetype != (dns_rdatatype_t)0) { + result = dns_db_findrdataset(db, node, ver, privatetype, + 0, (isc_stdtime_t) 0, + &privateset, NULL); + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) + goto failure; + } + + /* + * Look to see if we also need to be creating a NSEC3 chains. + */ + if (dns_rdataset_isassociated(&nsecset)) { + if (build_nsec != NULL) + *build_nsec = ISC_TRUE; + if (build_nsec3 != NULL) + *build_nsec3 = ISC_FALSE; + if (!dns_rdataset_isassociated(&privateset)) + goto success; + for (result = dns_rdataset_first(&privateset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&privateset)) { + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + dns_rdata_t private = DNS_RDATA_INIT; + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(&privateset, &private); + if (!dns_nsec3param_fromprivate(&private, &rdata, + buf, sizeof(buf))) + continue; + if (REMOVE(rdata.data[1])) + continue; + if (build_nsec3 != NULL) + *build_nsec3 = ISC_TRUE; + break; + } + goto success; + } + + if (dns_rdataset_isassociated(&nsec3paramset)) { + if (build_nsec3 != NULL) + *build_nsec3 = ISC_TRUE; + if (build_nsec != NULL) + *build_nsec = ISC_FALSE; + if (!dns_rdataset_isassociated(&privateset)) + goto success; + /* + * If we are in the process of building a new NSEC3 chain + * then we don't need to build a NSEC chain. + */ + for (result = dns_rdataset_first(&privateset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&privateset)) { + dns_rdata_t private = DNS_RDATA_INIT; + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(&privateset, &private); + if (!dns_nsec3param_fromprivate(&private, &rdata, + buf, sizeof(buf))) + continue; + if (CREATE(rdata.data[1])) + goto success; + } + + /* + * Check to see if there will be a active NSEC3CHAIN once + * the changes queued complete. + */ + count = 0; + for (result = dns_rdataset_first(&nsec3paramset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&nsec3paramset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + /* + * If there is more that one NSEC3 chain present then + * we don't need to construct a NSEC chain. + */ + if (++count > 1) + goto success; + dns_rdataset_current(&nsec3paramset, &rdata); + if (ignore(&rdata, &privateset)) + continue; + /* + * We still have a good NSEC3 chain or we are + * not creating a NSEC chain as NONSEC is set. + */ + goto success; + } + + /* + * The last NSEC3 chain is being removed and does not have + * have NONSEC set. + */ + if (build_nsec != NULL) + *build_nsec = ISC_TRUE; + goto success; + } + + if (build_nsec != NULL) + *build_nsec = ISC_FALSE; + if (build_nsec3 != NULL) + *build_nsec3 = ISC_FALSE; + if (!dns_rdataset_isassociated(&privateset)) + goto success; + + signing = ISC_FALSE; + nsec3chain = ISC_FALSE; + + for (result = dns_rdataset_first(&privateset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&privateset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_t private = DNS_RDATA_INIT; + + dns_rdataset_current(&privateset, &private); + if (!dns_nsec3param_fromprivate(&private, &rdata, + buf, sizeof(buf))) { + /* + * Look for record that says we are signing the + * zone with a key. + */ + if (private.length == 5 && private.data[0] != 0 && + private.data[3] == 0 && private.data[4] == 0) + signing = ISC_TRUE; + } else { + if (CREATE(rdata.data[1])) + nsec3chain = ISC_TRUE; + } + } + + if (signing) { + if (nsec3chain) { + if (build_nsec3 != NULL) + *build_nsec3 = ISC_TRUE; + } else { + if (build_nsec != NULL) + *build_nsec = ISC_TRUE; + } + } + + success: + result = ISC_R_SUCCESS; + failure: + if (dns_rdataset_isassociated(&nsecset)) + dns_rdataset_disassociate(&nsecset); + if (dns_rdataset_isassociated(&nsec3paramset)) + dns_rdataset_disassociate(&nsec3paramset); + if (dns_rdataset_isassociated(&privateset)) + dns_rdataset_disassociate(&privateset); + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); +} diff --git a/lib/dns/rbt.c b/lib/dns/rbt.c index 5e09db3..6c14e8e 100644 --- a/lib/dns/rbt.c +++ b/lib/dns/rbt.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbt.c,v 1.142.50.3 2009-10-20 05:06:04 marka Exp $ */ +/* $Id: rbt.c,v 1.146 2009-10-27 04:46:58 marka Exp $ */ /*! \file */ @@ -537,7 +537,10 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) { * current node. */ new_current->is_root = current->is_root; - new_current->nsec3 = current->nsec3; + if (current->nsec == DNS_RBT_NSEC_HAS_NSEC) + new_current->nsec = DNS_RBT_NSEC_NORMAL; + else + new_current->nsec = current->nsec; PARENT(new_current) = PARENT(current); LEFT(new_current) = LEFT(current); RIGHT(new_current) = RIGHT(current); @@ -1451,7 +1454,7 @@ create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep) { DIRTY(node) = 0; dns_rbtnode_refinit(node, 0); node->find_callback = 0; - node->nsec3 = 0; + node->nsec = DNS_RBT_NSEC_NORMAL; MAKE_BLACK(node); diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 87b70e3..d4415d8 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbtdb.c,v 1.270.12.26.4.1 2011-06-21 20:13:23 each Exp $ */ +/* $Id: rbtdb.c,v 1.310.8.1.2.1 2011-06-21 20:15:48 each Exp $ */ /*! \file */ @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -441,7 +442,9 @@ typedef struct { /* Locked by tree_lock. */ dns_rbt_t * tree; + dns_rbt_t * nsec; dns_rbt_t * nsec3; + dns_rpz_cidr_t * rpz_cidr; /* Unlocked */ unsigned int quantum; @@ -621,8 +624,9 @@ typedef struct rbtdb_dbiterator { static void free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event); static void overmem(dns_db_t *db, isc_boolean_t overmem); -static void setnsec3parameters(dns_db_t *db, rbtdb_version_t *version, - isc_boolean_t *nsec3createflag); +#ifdef BIND9 +static void setnsec3parameters(dns_db_t *db, rbtdb_version_t *version); +#endif /*% * 'init_count' is used to initialize 'newheader->count' which inturn @@ -830,6 +834,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) { isc_ondestroy_t ondest; isc_result_t result; char buf[DNS_NAME_FORMATSIZE]; + dns_rbt_t **treep; isc_time_t start; if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in) @@ -866,33 +871,26 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) { if (event == NULL) rbtdb->quantum = (rbtdb->task != NULL) ? 100 : 0; - again: - if (rbtdb->tree != NULL) { - isc_time_now(&start); - result = dns_rbt_destroy2(&rbtdb->tree, rbtdb->quantum); - if (result == ISC_R_QUOTA) { - INSIST(rbtdb->task != NULL); - if (rbtdb->quantum != 0) - rbtdb->quantum = adjust_quantum(rbtdb->quantum, - &start); - if (event == NULL) - event = isc_event_allocate(rbtdb->common.mctx, - NULL, - DNS_EVENT_FREESTORAGE, - free_rbtdb_callback, - rbtdb, - sizeof(isc_event_t)); - if (event == NULL) - goto again; - isc_task_send(rbtdb->task, &event); - return; + + for (;;) { + /* + * pick the next tree to (start to) destroy + */ + treep = &rbtdb->tree; + if (*treep == NULL) { + treep = &rbtdb->nsec; + if (*treep == NULL) { + treep = &rbtdb->nsec3; + /* + * we're finished after clear cutting + */ + if (*treep == NULL) + break; + } } - INSIST(result == ISC_R_SUCCESS && rbtdb->tree == NULL); - } - if (rbtdb->nsec3 != NULL) { isc_time_now(&start); - result = dns_rbt_destroy2(&rbtdb->nsec3, rbtdb->quantum); + result = dns_rbt_destroy2(treep, rbtdb->quantum); if (result == ISC_R_QUOTA) { INSIST(rbtdb->task != NULL); if (rbtdb->quantum != 0) @@ -906,11 +904,11 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) { rbtdb, sizeof(isc_event_t)); if (event == NULL) - goto again; + continue; isc_task_send(rbtdb->task, &event); return; } - INSIST(result == ISC_R_SUCCESS && rbtdb->nsec3 == NULL); + INSIST(result == ISC_R_SUCCESS && *treep == NULL); } if (event != NULL) @@ -965,6 +963,11 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) { if (rbtdb->rrsetstats != NULL) dns_stats_detach(&rbtdb->rrsetstats); +#ifdef BIND9 + if (rbtdb->rpz_cidr != NULL) + dns_rpz_cidr_free(&rbtdb->rpz_cidr); +#endif + isc_mem_put(rbtdb->common.mctx, rbtdb->node_locks, rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t)); isc_rwlock_destroy(&rbtdb->tree_lock); @@ -1488,6 +1491,82 @@ clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, node->dirty = 0; } +static void +delete_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) +{ + dns_rbtnode_t *nsecnode; + dns_fixedname_t fname; + dns_name_t *name; + isc_result_t result = ISC_R_UNEXPECTED; + + INSIST(!ISC_LINK_LINKED(node, deadlink)); + + switch (node->nsec) { + case DNS_RBT_NSEC_NORMAL: +#ifdef BIND9 + if (rbtdb->rpz_cidr != NULL) { + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + dns_rbt_fullnamefromnode(node, name); + dns_rpz_cidr_deleteip(rbtdb->rpz_cidr, name); + } +#endif + result = dns_rbt_deletenode(rbtdb->tree, node, ISC_FALSE); + break; + case DNS_RBT_NSEC_HAS_NSEC: + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + dns_rbt_fullnamefromnode(node, name); + /* + * Delete the corresponding node from the auxiliary NSEC + * tree before deleting from the main tree. + */ + nsecnode = NULL; + result = dns_rbt_findnode(rbtdb->nsec, name, NULL, &nsecnode, + NULL, DNS_RBTFIND_EMPTYDATA, + NULL, NULL); + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE, ISC_LOG_WARNING, + "delete_node: " + "dns_rbt_findnode(nsec): %s", + isc_result_totext(result)); + } else { + result = dns_rbt_deletenode(rbtdb->nsec, nsecnode, + ISC_FALSE); + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE, + ISC_LOG_WARNING, + "delete_nsecnode(): " + "dns_rbt_deletenode(nsecnode): %s", + isc_result_totext(result)); + } + } + result = dns_rbt_deletenode(rbtdb->tree, node, ISC_FALSE); +#ifdef BIND9 + dns_rpz_cidr_deleteip(rbtdb->rpz_cidr, name); +#endif + break; + case DNS_RBT_NSEC_NSEC: + result = dns_rbt_deletenode(rbtdb->nsec, node, ISC_FALSE); + break; + case DNS_RBT_NSEC_NSEC3: + result = dns_rbt_deletenode(rbtdb->nsec3, node, ISC_FALSE); + break; + } + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE, + ISC_LOG_WARNING, + "delete_nsecnode(): " + "dns_rbt_deletenode: %s", + isc_result_totext(result)); + } +} + /*% * Clean up dead nodes. These are nodes which have no references, and * have no data. They are dead but we could not or chose not to delete @@ -1499,7 +1578,6 @@ clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, static void cleanup_dead_nodes(dns_rbtdb_t *rbtdb, int bucketnum) { dns_rbtnode_t *node; - isc_result_t result; int count = 10; /* XXXJT: should be adjustable */ node = ISC_LIST_HEAD(rbtdb->deadnodes[bucketnum]); @@ -1513,19 +1591,8 @@ cleanup_dead_nodes(dns_rbtdb_t *rbtdb, int bucketnum) { INSIST(dns_rbtnode_refcurrent(node) == 0 && node->data == NULL); - INSIST(!ISC_LINK_LINKED(node, deadlink)); - if (node->nsec3) - result = dns_rbt_deletenode(rbtdb->nsec3, node, - ISC_FALSE); - else - result = dns_rbt_deletenode(rbtdb->tree, node, - ISC_FALSE); - if (result != ISC_R_SUCCESS) - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_CACHE, ISC_LOG_WARNING, - "cleanup_dead_nodes: " - "dns_rbt_deletenode: %s", - isc_result_totext(result)); + delete_node(rbtdb, node); + node = ISC_LIST_HEAD(rbtdb->deadnodes[bucketnum]); count--; } @@ -1774,22 +1841,7 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, sizeof(printname))); } - INSIST(!ISC_LINK_LINKED(node, deadlink)); - if (node->nsec3) - result = dns_rbt_deletenode(rbtdb->nsec3, node, - ISC_FALSE); - else - result = dns_rbt_deletenode(rbtdb->tree, node, - ISC_FALSE); - if (result != ISC_R_SUCCESS) { - isc_log_write(dns_lctx, - DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_CACHE, - ISC_LOG_WARNING, - "decrement_reference: " - "dns_rbt_deletenode: %s", - isc_result_totext(result)); - } + delete_node(rbtdb, node); } } else if (dns_rbtnode_refcurrent(node) == 0) { INSIST(!ISC_LINK_LINKED(node, deadlink)); @@ -1925,13 +1977,17 @@ cleanup_nondirty(rbtdb_version_t *version, rbtdb_changedlist_t *cleanup_list) { static void iszonesecure(dns_db_t *db, rbtdb_version_t *version, dns_dbnode_t *origin) { +#ifndef BIND9 + UNUSED(db); + UNUSED(version); + UNUSED(origin); + + return; +#else dns_rdataset_t keyset; dns_rdataset_t nsecset, signsecset; - dns_rdata_t rdata = DNS_RDATA_INIT; isc_boolean_t haszonekey = ISC_FALSE; isc_boolean_t hasnsec = ISC_FALSE; - isc_boolean_t hasoptbit = ISC_FALSE; - isc_boolean_t nsec3createflag = ISC_FALSE; isc_result_t result; dns_rdataset_init(&keyset); @@ -1963,41 +2019,30 @@ iszonesecure(dns_db_t *db, rbtdb_version_t *version, dns_dbnode_t *origin) { if (result == ISC_R_SUCCESS) { if (dns_rdataset_isassociated(&signsecset)) { hasnsec = ISC_TRUE; - result = dns_rdataset_first(&nsecset); - if (result == ISC_R_SUCCESS) { - dns_rdataset_current(&nsecset, &rdata); - hasoptbit = dns_nsec_typepresent(&rdata, - dns_rdatatype_opt); - } dns_rdataset_disassociate(&signsecset); } dns_rdataset_disassociate(&nsecset); } - setnsec3parameters(db, version, &nsec3createflag); + setnsec3parameters(db, version); /* * Do we have a valid NSEC/NSEC3 chain? */ - if (version->havensec3 || (hasnsec && !hasoptbit)) + if (version->havensec3 || hasnsec) version->secure = dns_db_secure; - /* - * Do we have a NSEC/NSEC3 chain under creation? - */ - else if (hasoptbit || nsec3createflag) - version->secure = dns_db_partial; else version->secure = dns_db_insecure; +#endif } /*%< * Walk the origin node looking for NSEC3PARAM records. * Cache the nsec3 parameters. */ +#ifdef BIND9 static void -setnsec3parameters(dns_db_t *db, rbtdb_version_t *version, - isc_boolean_t *nsec3createflag) -{ +setnsec3parameters(dns_db_t *db, rbtdb_version_t *version) { dns_rbtnode_t *node; dns_rdata_nsec3param_t nsec3param; dns_rdata_t rdata = DNS_RDATA_INIT; @@ -2028,7 +2073,7 @@ setnsec3parameters(dns_db_t *db, rbtdb_version_t *version, } while (header != NULL); if (header != NULL && - header->type == dns_rdatatype_nsec3param) { + (header->type == dns_rdatatype_nsec3param)) { /* * Find A NSEC3PARAM with a supported algorithm. */ @@ -2063,17 +2108,8 @@ setnsec3parameters(dns_db_t *db, rbtdb_version_t *version, !dns_nsec3_supportedhash(nsec3param.hash)) continue; -#ifdef RFC5155_STRICT if (nsec3param.flags != 0) continue; -#else - if ((nsec3param.flags & DNS_NSEC3FLAG_CREATE) - != 0) - *nsec3createflag = ISC_TRUE; - if ((nsec3param.flags & ~DNS_NSEC3FLAG_OPTOUT) - != 0) - continue; -#endif memcpy(version->salt, nsec3param.salt, nsec3param.salt_length); @@ -2096,6 +2132,7 @@ setnsec3parameters(dns_db_t *db, rbtdb_version_t *version, isc_rwlocktype_read); RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); } +#endif static void cleanup_dead_nodes_callback(isc_task_t *task, isc_event_t *event) { @@ -2415,7 +2452,8 @@ add_wildcard_magic(dns_rbtdb_t *rbtdb, dns_name_t *name) { result = dns_rbt_addnode(rbtdb->tree, &foundname, &node); if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) return (result); - node->nsec3 = 0; + if (result == ISC_R_SUCCESS) + node->nsec = DNS_RBT_NSEC_NORMAL; node->find_callback = 1; node->wild = 1; return (ISC_R_SUCCESS); @@ -2443,7 +2481,8 @@ add_empty_wildcards(dns_rbtdb_t *rbtdb, dns_name_t *name) { &node); if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) return (result); - node->nsec3 = 0; + if (result == ISC_R_SUCCESS) + node->nsec = DNS_RBT_NSEC_NORMAL; } i++; } @@ -2482,6 +2521,17 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, node = NULL; result = dns_rbt_addnode(rbtdb->tree, name, &node); if (result == ISC_R_SUCCESS) { +#ifdef BIND9 + if (rbtdb->rpz_cidr != NULL) { + dns_fixedname_t fnamef; + dns_name_t *fname; + + dns_fixedname_init(&fnamef); + fname = dns_fixedname_name(&fnamef); + dns_rbt_fullnamefromnode(node, fname); + dns_rpz_cidr_addip(rbtdb->rpz_cidr, fname); + } +#endif dns_rbt_namefromnode(node, &nodename); #ifdef DNS_RBT_USEHASH node->locknum = node->hashval % rbtdb->node_lock_count; @@ -2489,7 +2539,6 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, node->locknum = dns_name_hash(&nodename, ISC_TRUE) % rbtdb->node_lock_count; #endif - node->nsec3 = 0; add_empty_wildcards(rbtdb, name); if (dns_name_iswildcard(name)) { @@ -2551,13 +2600,14 @@ findnsec3node(dns_db_t *db, dns_name_t *name, isc_boolean_t create, node->locknum = dns_name_hash(&nodename, ISC_TRUE) % rbtdb->node_lock_count; #endif - node->nsec3 = 1U; + node->nsec = DNS_RBT_NSEC_NSEC3; } else if (result != ISC_R_EXISTS) { RWUNLOCK(&rbtdb->tree_lock, locktype); return (result); } - } else - INSIST(node->nsec3); + } else { + INSIST(node->nsec == DNS_RBT_NSEC_NSEC3); + } NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock); new_reference(rbtdb, node); NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock); @@ -3268,13 +3318,125 @@ matchparams(rdatasetheader_t *header, rbtdb_search_t *search) * Find node of the NSEC/NSEC3 record that is 'name'. */ static inline isc_result_t +previous_closest_nsec(dns_rdatatype_t type, rbtdb_search_t *search, + dns_name_t *name, dns_name_t *origin, + dns_rbtnode_t **nodep, dns_rbtnodechain_t *nsecchain, + isc_boolean_t *firstp) +{ + dns_fixedname_t ftarget; + dns_name_t *target; + dns_rbtnode_t *nsecnode; + isc_result_t result; + + REQUIRE(nodep != NULL && *nodep == NULL); + + if (type == dns_rdatatype_nsec3) { + result = dns_rbtnodechain_prev(&search->chain, NULL, NULL); + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) + return (result); + result = dns_rbtnodechain_current(&search->chain, name, origin, + nodep); + return (result); + } + + dns_fixedname_init(&ftarget); + target = dns_fixedname_name(&ftarget); + + for (;;) { + if (*firstp) { + /* + * Construct the name of the second node to check. + * It is the first node sought in the NSEC tree. + */ + *firstp = ISC_FALSE; + dns_rbtnodechain_init(nsecchain, NULL); + result = dns_name_concatenate(name, origin, + target, NULL); + if (result != ISC_R_SUCCESS) + return (result); + nsecnode = NULL; + result = dns_rbt_findnode(search->rbtdb->nsec, + target, NULL, + &nsecnode, nsecchain, + DNS_RBTFIND_NOOPTIONS, + NULL, NULL); + if (result == ISC_R_SUCCESS) { + /* + * Since this was the first loop, finding the + * name in the NSEC tree implies that the first + * node checked in the main tree had an + * unacceptable NSEC record. + * Try the previous node in the NSEC tree. + */ + result = dns_rbtnodechain_prev(nsecchain, + name, origin); + if (result == DNS_R_NEWORIGIN) + result = ISC_R_SUCCESS; + } else if (result == ISC_R_NOTFOUND || + result == DNS_R_PARTIALMATCH) { + result = dns_rbtnodechain_current(nsecchain, + name, origin, NULL); + if (result == ISC_R_NOTFOUND) + result = ISC_R_NOMORE; + } + } else { + /* + * This is a second or later trip through the auxiliary + * tree for the name of a third or earlier NSEC node in + * the main tree. Previous trips through the NSEC tree + * must have found nodes in the main tree with NSEC + * records. Perhaps they lacked signature records. + */ + result = dns_rbtnodechain_prev(nsecchain, name, origin); + if (result == DNS_R_NEWORIGIN) + result = ISC_R_SUCCESS; + } + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Construct the name to seek in the main tree. + */ + result = dns_name_concatenate(name, origin, target, NULL); + if (result != ISC_R_SUCCESS) + return (result); + + *nodep = NULL; + result = dns_rbt_findnode(search->rbtdb->tree, target, NULL, + nodep, &search->chain, + DNS_RBTFIND_NOOPTIONS, NULL, NULL); + if (result == ISC_R_SUCCESS) + return (result); + + /* + * There should always be a node in the main tree with the + * same name as the node in the auxiliary NSEC tree, except for + * nodes in the auxiliary tree that are awaiting deletion. + */ + if (result != DNS_R_PARTIALMATCH && result != ISC_R_NOTFOUND) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE, ISC_LOG_ERROR, + "previous_closest_nsec(): %s", + isc_result_totext(result)); + return (DNS_R_BADDB); + } + } +} + +/* + * Find the NSEC/NSEC3 which is or before the current point on the + * search chain. For NSEC3 records only NSEC3 records that match the + * current NSEC3PARAM record are considered. + */ +static inline isc_result_t find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, dns_rbt_t *tree, dns_db_secure_t secure) { - dns_rbtnode_t *node; + dns_rbtnode_t *node, *prevnode; rdatasetheader_t *header, *header_next, *found, *foundsig; + dns_rbtnodechain_t nsecchain; isc_boolean_t empty_node; isc_result_t result; dns_fixedname_t fname, forigin; @@ -3282,6 +3444,7 @@ find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep, dns_rdatatype_t type; rbtdb_rdatatype_t sigtype; isc_boolean_t wraps; + isc_boolean_t first = ISC_TRUE; isc_boolean_t need_sig = ISC_TF(secure == dns_db_secure); if (tree == search->rbtdb->nsec3) { @@ -3294,17 +3457,21 @@ find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep, wraps = ISC_FALSE; } + /* + * Use the auxiliary tree only starting with the second node in the + * hope that the original node will be right much of the time. + */ + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + dns_fixedname_init(&forigin); + origin = dns_fixedname_name(&forigin); again: + node = NULL; + prevnode = NULL; + result = dns_rbtnodechain_current(&search->chain, name, origin, &node); + if (result != ISC_R_SUCCESS) + return (result); do { - node = NULL; - dns_fixedname_init(&fname); - name = dns_fixedname_name(&fname); - dns_fixedname_init(&forigin); - origin = dns_fixedname_name(&forigin); - result = dns_rbtnodechain_current(&search->chain, name, - origin, &node); - if (result != ISC_R_SUCCESS) - return (result); NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock), isc_rwlocktype_read); found = NULL; @@ -3354,11 +3521,12 @@ find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep, empty_node = ISC_TRUE; found = NULL; foundsig = NULL; - result = dns_rbtnodechain_prev(&search->chain, - NULL, NULL); + result = previous_closest_nsec(type, search, + name, origin, + &prevnode, NULL, + NULL); } else if (found != NULL && - (foundsig != NULL || !need_sig)) - { + (foundsig != NULL || !need_sig)) { /* * We've found the right NSEC/NSEC3 record. * @@ -3395,8 +3563,11 @@ find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep, * node as if it were empty and keep looking. */ empty_node = ISC_TRUE; - result = dns_rbtnodechain_prev(&search->chain, - NULL, NULL); + result = previous_closest_nsec(type, search, + name, origin, + &prevnode, + &nsecchain, + &first); } else { /* * We found an active node, but either the @@ -3410,13 +3581,19 @@ find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep, * This node isn't active. We've got to keep * looking. */ - result = dns_rbtnodechain_prev(&search->chain, NULL, - NULL); + result = previous_closest_nsec(type, search, + name, origin, &prevnode, + &nsecchain, &first); } NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock), isc_rwlocktype_read); + node = prevnode; + prevnode = NULL; } while (empty_node && result == ISC_R_SUCCESS); + if (!first) + dns_rbtnodechain_invalidate(&nsecchain); + if (result == ISC_R_NOMORE && wraps) { result = dns_rbtnodechain_last(&search->chain, tree, NULL, NULL); @@ -3960,6 +4137,7 @@ zone_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options, FATAL_ERROR(__FILE__, __LINE__, "zone_findzonecut() called!"); + /* NOTREACHED */ return (ISC_R_NOTIMPLEMENTED); } @@ -4371,6 +4549,200 @@ find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep, return (result); } +/* + * Mark a database for response policy rewriting. + */ +#ifdef BIND9 +static void +get_rpz_enabled(dns_db_t *db, dns_rpz_st_t *st) +{ + dns_rbtdb_t *rbtdb; + + rbtdb = (dns_rbtdb_t *)db; + REQUIRE(VALID_RBTDB(rbtdb)); + RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + dns_rpz_enabled(rbtdb->rpz_cidr, st); + RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); +} + +/* + * Search the CDIR block tree of a response policy tree of trees for all of + * the IP addresses in an A or AAAA rdataset. + * Among the policies for all IPv4 and IPv6 addresses for a name, choose + * the longest prefix. Among those with the longest prefix, the first + * configured policy. Among answers for with the longest prefixes for + * two or more IP addresses in the A and AAAA rdatasets the lexically + * smallest address. + */ +static isc_result_t +rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type, + dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, + dns_rdataset_t *ardataset, dns_rpz_st_t *st) +{ + dns_rbtdb_t *rbtdb; + struct in_addr ina; + struct in6_addr in6a; + isc_netaddr_t netaddr; + dns_fixedname_t selfnamef, qnamef; + dns_name_t *selfname, *qname; + dns_rbtnode_t *node; + dns_rdataset_t zrdataset; + dns_rpz_cidr_bits_t prefix; + isc_result_t result; + dns_rpz_policy_t rpz_policy; + dns_ttl_t ttl; + + rbtdb = (dns_rbtdb_t *)db; + REQUIRE(VALID_RBTDB(rbtdb)); + RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + + if (rbtdb->rpz_cidr == NULL) { + RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + dns_db_detach(&db); + dns_zone_detach(&zone); + return (ISC_R_UNEXPECTED); + } + + dns_fixedname_init(&selfnamef); + dns_fixedname_init(&qnamef); + selfname = dns_fixedname_name(&selfnamef); + qname = dns_fixedname_name(&qnamef); + + for (result = dns_rdataset_first(ardataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(ardataset)) { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_current(ardataset, &rdata); + switch (rdata.type) { + case dns_rdatatype_a: + INSIST(rdata.length == 4); + memcpy(&ina.s_addr, rdata.data, 4); + isc_netaddr_fromin(&netaddr, &ina); + break; + case dns_rdatatype_aaaa: + INSIST(rdata.length == 16); + memcpy(in6a.s6_addr, rdata.data, 16); + isc_netaddr_fromin6(&netaddr, &in6a); + break; + default: + continue; + } + + result = dns_rpz_cidr_find(rbtdb->rpz_cidr, &netaddr, rpz_type, + selfname, qname, &prefix); + if (result != ISC_R_SUCCESS) + continue; + + /* + * Choose the policy with the longest matching prefix. + * Between policies with the same prefix, choose the first + * configured. + */ + if (st->m.policy != DNS_RPZ_POLICY_MISS) { + if (prefix < st->m.prefix) + continue; + if (prefix == st->m.prefix && + rpz->num > st->m.rpz->num) + continue; + } + + /* + * We have rpz_st an entry with a prefix at least as long as + * the prefix of the entry we had before. Find the node + * corresponding to CDIR tree entry. + */ + node = NULL; + result = dns_rbt_findnode(rbtdb->tree, qname, NULL, + &node, NULL, 0, NULL, NULL); + if (result != ISC_R_SUCCESS) { + char namebuf[DNS_NAME_FORMATSIZE]; + + dns_name_format(qname, namebuf, sizeof(namebuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE, DNS_RPZ_ERROR_LEVEL, + "rpz_findips findnode(%s): %s", + namebuf, isc_result_totext(result)); + continue; + } + /* + * First look for a simple rewrite of the IP address. + * If that fails, look for a CNAME. If we cannot find + * a CNAME or the CNAME is neither of the special forms + * "*" or ".", treat it like a real CNAME. + */ + dns_rdataset_init(&zrdataset); + result = dns_db_findrdataset(db, node, version, ardataset->type, + 0, 0, &zrdataset, NULL); + if (result != ISC_R_SUCCESS) + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_cname, + 0, 0, &zrdataset, NULL); + if (result == ISC_R_SUCCESS) { + if (zrdataset.type != dns_rdatatype_cname) { + rpz_policy = DNS_RPZ_POLICY_RECORD; + } else { + rpz_policy = dns_rpz_decode_cname(&zrdataset, + selfname); + if (rpz_policy == DNS_RPZ_POLICY_RECORD) + result = DNS_R_CNAME; + } + ttl = zrdataset.ttl; + } else { + rpz_policy = DNS_RPZ_POLICY_RECORD; + result = DNS_R_NXRRSET; + ttl = DNS_RPZ_TTL_DEFAULT; + } + + /* + * Use an overriding action specified in the configuration file + */ + if (rpz->policy != DNS_RPZ_POLICY_GIVEN && + rpz_policy != DNS_RPZ_POLICY_NO_OP) + rpz_policy = rpz->policy; + + /* + * We know the new prefix is at least as long as the current. + * Prefer the new answer if the new prefix is longer. + * Prefer the zone configured first if the prefixes are equal. + * With two actions from the same zone, prefer the action + * on the "smallest" name. + */ + if (st->m.policy == DNS_RPZ_POLICY_MISS || + prefix > st->m.prefix || + rpz->num <= st->m.rpz->num || + 0 > dns_name_compare(qname, st->qname)) { + if (dns_rdataset_isassociated(st->m.rdataset)) + dns_rdataset_disassociate(st->m.rdataset); + if (st->m.node != NULL) + dns_db_detachnode(st->m.db, &st->m.node); + if (st->m.db != NULL) + dns_db_detach(&st->m.db); + if (st->m.zone != NULL) + dns_zone_detach(&st->m.zone); + st->m.rpz = rpz; + st->m.type = rpz_type; + st->m.prefix = prefix; + st->m.policy = rpz_policy; + st->m.ttl = ttl; + st->m.result = result; + dns_name_copy(qname, st->qname, NULL); + if (rpz_policy == DNS_RPZ_POLICY_RECORD && + result != DNS_R_NXRRSET) { + dns_rdataset_clone(&zrdataset,st->m.rdataset); + dns_db_attachnode(db, node, &st->m.node); + } + dns_db_attach(db, &st->m.db); + dns_zone_attach(zone, &st->m.zone); + } + if (dns_rdataset_isassociated(&zrdataset)) + dns_rdataset_disassociate(&zrdataset); + } + + RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + return (ISC_R_SUCCESS); +} +#endif + static isc_result_t cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, @@ -5693,6 +6065,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, free_rdataset(rbtdb, rbtdb->common.mctx, newheader); newheader = (rdatasetheader_t *)merged; + init_rdataset(rbtdb, newheader); if (loading && RESIGN(newheader) && RESIGN(header) && header->resign < newheader->resign) @@ -6015,16 +6388,17 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, rdatasetheader_t *header; isc_result_t result; isc_boolean_t delegating; + isc_boolean_t newnsec; isc_boolean_t tree_locked = ISC_FALSE; isc_boolean_t cache_is_overmem = ISC_FALSE; REQUIRE(VALID_RBTDB(rbtdb)); if (rbtdb->common.methods == &zone_methods) - REQUIRE(((rbtnode->nsec3 && + REQUIRE(((rbtnode->nsec == DNS_RBT_NSEC_NSEC3 && (rdataset->type == dns_rdatatype_nsec3 || rdataset->covers == dns_rdatatype_nsec3)) || - (!rbtnode->nsec3 && + (rbtnode->nsec != DNS_RBT_NSEC_NSEC3 && rdataset->type != dns_rdatatype_nsec3 && rdataset->covers != dns_rdatatype_nsec3))); @@ -6101,14 +6475,23 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, delegating = ISC_FALSE; /* - * If we're adding a delegation type or the DB is a cache in an overmem - * state, hold an exclusive lock on the tree. In the latter case - * the lock does not necessarily have to be acquired but it will help - * purge stale entries more effectively. + * Add to the auxiliary NSEC tree if we're adding an NSEC record. + */ + if (rbtnode->nsec != DNS_RBT_NSEC_HAS_NSEC && + rdataset->type == dns_rdatatype_nsec) + newnsec = ISC_TRUE; + else + newnsec = ISC_FALSE; + + /* + * If we're adding a delegation type, adding to the auxiliary NSEC tree, + * or the DB is a cache in an overmem state, hold an exclusive lock on + * the tree. In the latter case the lock does not necessarily have to + * be acquired but it will help purge stale entries more effectively. */ if (IS_CACHE(rbtdb) && isc_mem_isovermem(rbtdb->common.mctx)) cache_is_overmem = ISC_TRUE; - if (delegating || cache_is_overmem) { + if (delegating || newnsec || cache_is_overmem) { tree_locked = ISC_TRUE; RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); } @@ -6137,14 +6520,35 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, * cleaning, we can release it now. However, we still need the * node lock. */ - if (tree_locked && !delegating) { + if (tree_locked && !delegating && !newnsec) { RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); tree_locked = ISC_FALSE; } } - result = add(rbtdb, rbtnode, rbtversion, newheader, options, ISC_FALSE, - addedrdataset, now); + result = ISC_R_SUCCESS; + if (newnsec) { + dns_fixedname_t fname; + dns_name_t *name; + dns_rbtnode_t *nsecnode; + + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + dns_rbt_fullnamefromnode(rbtnode, name); + nsecnode = NULL; + result = dns_rbt_addnode(rbtdb->nsec, name, &nsecnode); + if (result == ISC_R_SUCCESS) { + nsecnode->nsec = DNS_RBT_NSEC_NSEC; + rbtnode->nsec = DNS_RBT_NSEC_HAS_NSEC; + } else if (result == ISC_R_EXISTS) { + rbtnode->nsec = DNS_RBT_NSEC_HAS_NSEC; + result = ISC_R_SUCCESS; + } + } + + if (result == ISC_R_SUCCESS) + result = add(rbtdb, rbtnode, rbtversion, newheader, options, + ISC_FALSE, addedrdataset, now); if (result == ISC_R_SUCCESS && delegating) rbtnode->find_callback = 1; @@ -6181,10 +6585,10 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, REQUIRE(VALID_RBTDB(rbtdb)); if (rbtdb->common.methods == &zone_methods) - REQUIRE(((rbtnode->nsec3 && + REQUIRE(((rbtnode->nsec == DNS_RBT_NSEC_NSEC3 && (rdataset->type == dns_rdatatype_nsec3 || rdataset->covers == dns_rdatatype_nsec3)) || - (!rbtnode->nsec3 && + (rbtnode->nsec != DNS_RBT_NSEC_NSEC3 && rdataset->type != dns_rdatatype_nsec3 && rdataset->covers != dns_rdatatype_nsec3))); @@ -6403,6 +6807,78 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, return (result); } +/* + * load a non-NSEC3 node in the main tree and optionally to the auxiliary NSEC + */ +static isc_result_t +loadnode(dns_rbtdb_t *rbtdb, dns_name_t *name, dns_rbtnode_t **nodep, + isc_boolean_t hasnsec) +{ + isc_result_t noderesult, nsecresult; + dns_rbtnode_t *nsecnode; + + noderesult = dns_rbt_addnode(rbtdb->tree, name, nodep); + +#ifdef BIND9 + if (noderesult == ISC_R_SUCCESS) + dns_rpz_cidr_addip(rbtdb->rpz_cidr, name); +#endif + + if (!hasnsec) + return (noderesult); + if (noderesult == ISC_R_EXISTS) { + /* + * Add a node to the auxiliary NSEC tree for an old node + * just now getting an NSEC record. + */ + if ((*nodep)->nsec == DNS_RBT_NSEC_HAS_NSEC) + return (noderesult); + } else if (noderesult != ISC_R_SUCCESS) { + return (noderesult); + } + + /* + * Build the auxiliary tree for NSECs as we go. + * This tree speeds searches for closest NSECs that would otherwise + * need to examine many irrelevant nodes in large TLDs. + * + * Add nodes to the auxiliary tree after corresponding nodes have + * been added to the main tree. + */ + nsecnode = NULL; + nsecresult = dns_rbt_addnode(rbtdb->nsec, name, &nsecnode); + if (nsecresult == ISC_R_SUCCESS) { + nsecnode->nsec = DNS_RBT_NSEC_NSEC; + (*nodep)->nsec = DNS_RBT_NSEC_HAS_NSEC; + return (noderesult); + } + + if (nsecresult == ISC_R_EXISTS) { +#if 1 /* 0 */ + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE, + ISC_LOG_WARNING, + "addnode: NSEC node already exists"); +#endif + (*nodep)->nsec = DNS_RBT_NSEC_HAS_NSEC; + return (noderesult); + } + + nsecresult = dns_rbt_deletenode(rbtdb->tree, *nodep, ISC_FALSE); + if (nsecresult != ISC_R_SUCCESS) + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_CACHE, + ISC_LOG_WARNING, + "loading_addrdataset: " + "dns_rbt_deletenode: %s after " + "dns_rbt_addnode(NSEC): %s", + isc_result_totext(nsecresult), + isc_result_totext(noderesult)); + return (noderesult); +} + static isc_result_t loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) { rbtdb_load_t *loadctx = arg; @@ -6451,15 +6927,15 @@ loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) { rdataset->covers == dns_rdatatype_nsec3) { result = dns_rbt_addnode(rbtdb->nsec3, name, &node); if (result == ISC_R_SUCCESS) - node->nsec3 = 1; + node->nsec = DNS_RBT_NSEC_NSEC3; + } else if (rdataset->type == dns_rdatatype_nsec) { + result = loadnode(rbtdb, name, &node, ISC_TRUE); } else { - result = dns_rbt_addnode(rbtdb->tree, name, &node); - if (result == ISC_R_SUCCESS) - node->nsec3 = 0; + result = loadnode(rbtdb, name, &node, ISC_FALSE); } if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) return (result); - if (result != ISC_R_EXISTS) { + if (result == ISC_R_SUCCESS) { dns_name_t foundname; dns_name_init(&foundname, NULL); dns_rbt_namefromnode(node, &foundname); @@ -6585,9 +7061,17 @@ dump(dns_db_t *db, dns_dbversion_t *version, const char *filename, REQUIRE(VALID_RBTDB(rbtdb)); +#ifdef BIND9 return (dns_master_dump2(rbtdb->common.mctx, db, version, &dns_master_style_default, filename, masterformat)); +#else + UNUSED(version); + UNUSED(filename); + UNUSED(masterformat); + + return (ISC_R_NOTIMPLEMENTED); +#endif /* BIND9 */ } static void @@ -6768,7 +7252,7 @@ setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) { } else if (resign < oldresign) isc_heap_increased(rbtdb->heaps[header->node->locknum], header->heap_index); - else + else if (resign > oldresign) isc_heap_decreased(rbtdb->heaps[header->node->locknum], header->heap_index); } else if (resign && header->heap_index == 0) { @@ -6913,7 +7397,14 @@ static dns_dbmethods_t zone_methods = { getsigningtime, resigned, isdnssec, + NULL, +#ifdef BIND9 + get_rpz_enabled, + rpz_findips +#else + NULL, NULL +#endif }; static dns_dbmethods_t cache_methods = { @@ -6952,7 +7443,9 @@ static dns_dbmethods_t cache_methods = { NULL, NULL, isdnssec, - getrrsetstats + getrrsetstats, + NULL, + NULL }; isc_result_t @@ -7122,12 +7615,36 @@ dns_rbtdb_create return (result); } + result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->nsec); + if (result != ISC_R_SUCCESS) { + free_rbtdb(rbtdb, ISC_FALSE, NULL); + return (result); + } + result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->nsec3); if (result != ISC_R_SUCCESS) { free_rbtdb(rbtdb, ISC_FALSE, NULL); return (result); } +#ifdef BIND9 + /* + * Get ready for response policy IP address searching if at least one + * zone has been configured as a response policy zone and this + * is not a cache zone. + * It would be better to know that this database is for a policy + * zone named for a view, but that would require knowledge from + * above such as an argv[] set from data in the zone. + */ + if (type == dns_dbtype_zone && !dns_name_equal(origin, dns_rootname)) { + result = dns_rpz_new_cidr(mctx, origin, &rbtdb->rpz_cidr); + if (result != ISC_R_SUCCESS) { + free_rbtdb(rbtdb, ISC_FALSE, NULL); + return (result); + } + } +#endif + /* * In order to set the node callback bit correctly in zone databases, * we need to know if the node has the origin name of the zone. @@ -7152,7 +7669,7 @@ dns_rbtdb_create free_rbtdb(rbtdb, ISC_FALSE, NULL); return (result); } - rbtdb->origin_node->nsec3 = 0; + rbtdb->origin_node->nsec = DNS_RBT_NSEC_NORMAL; /* * We need to give the origin node the right locknum. */ @@ -7180,7 +7697,7 @@ dns_rbtdb_create free_rbtdb(rbtdb, ISC_FALSE, NULL); return (result); } - nsec3node->nsec3 = 1; + nsec3node->nsec = DNS_RBT_NSEC_NSEC3; /* * We need to give the nsec3 origin node the right locknum. */ @@ -8238,6 +8755,21 @@ rdataset_getadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, dns_name_t *fname, dns_message_t *msg, isc_stdtime_t now) { +#ifndef BIND9 + UNUSED(rdataset); + UNUSED(type); + UNUSED(qtype); + UNUSED(acache); + UNUSED(zonep); + UNUSED(dbp); + UNUSED(versionp); + UNUSED(nodep); + UNUSED(fname); + UNUSED(msg); + UNUSED(now); + + return (ISC_R_NOTIMPLEMENTED); +#else dns_rbtdb_t *rbtdb = rdataset->private1; dns_rbtnode_t *rbtnode = rdataset->private2; unsigned char *raw = rdataset->private3; /* RDATASLAB */ @@ -8354,8 +8886,10 @@ acache_callback(dns_acacheentry_t *entry, void **arg) { dns_db_detach((dns_db_t **)(void*)&rbtdb); *arg = NULL; +#endif /* BIND9 */ } +#ifdef BIND9 static void acache_cancelentry(isc_mem_t *mctx, dns_acacheentry_t *entry, acache_cbarg_t **cbargp) @@ -8376,6 +8910,7 @@ acache_cancelentry(isc_mem_t *mctx, dns_acacheentry_t *entry, *cbargp = NULL; } +#endif /* BIND9 */ static isc_result_t rdataset_setadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, @@ -8384,6 +8919,19 @@ rdataset_setadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, dns_dbversion_t *version, dns_dbnode_t *node, dns_name_t *fname) { +#ifndef BIND9 + UNUSED(rdataset); + UNUSED(type); + UNUSED(qtype); + UNUSED(acache); + UNUSED(zone); + UNUSED(db); + UNUSED(version); + UNUSED(node); + UNUSED(fname); + + return (ISC_R_NOTIMPLEMENTED); +#else dns_rbtdb_t *rbtdb = rdataset->private1; dns_rbtnode_t *rbtnode = rdataset->private2; unsigned char *raw = rdataset->private3; /* RDATASLAB */ @@ -8507,12 +9055,21 @@ rdataset_setadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, } return (result); +#endif } static isc_result_t rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, dns_rdatatype_t qtype) { +#ifndef BIND9 + UNUSED(acache); + UNUSED(rdataset); + UNUSED(type); + UNUSED(qtype); + + return (ISC_R_NOTIMPLEMENTED); +#else dns_rbtdb_t *rbtdb = rdataset->private1; dns_rbtnode_t *rbtnode = rdataset->private2; unsigned char *raw = rdataset->private3; /* RDATASLAB */ @@ -8577,6 +9134,7 @@ rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset, } return (ISC_R_SUCCESS); +#endif } /*% diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c index 2dc0a29..18fedcd 100644 --- a/lib/dns/rcode.c +++ b/lib/dns/rcode.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rcode.c,v 1.8.48.2 2010-01-15 23:47:33 tbox Exp $ */ +/* $Id: rcode.c,v 1.16 2010-12-23 04:07:58 marka Exp $ */ #include #include @@ -79,12 +79,17 @@ { dns_tsigerror_badtrunc, "BADTRUNC", 0}, \ { 0, NULL, 0 } -/* RFC2538 section 2.1 */ +/* RFC4398 section 2.1 */ #define CERTNAMES \ { 1, "PKIX", 0}, \ { 2, "SPKI", 0}, \ { 3, "PGP", 0}, \ + { 4, "IPKIX", 0}, \ + { 5, "ISPKI", 0}, \ + { 6, "IPGP", 0}, \ + { 7, "ACPKIX", 0}, \ + { 8, "IACPKIX", 0}, \ { 253, "URI", 0}, \ { 254, "OID", 0}, \ { 0, NULL, 0} @@ -102,6 +107,7 @@ { DNS_KEYALG_NSEC3RSASHA1, "NSEC3RSASHA1", 0 }, \ { DNS_KEYALG_RSASHA256, "RSASHA256", 0 }, \ { DNS_KEYALG_RSASHA512, "RSASHA512", 0 }, \ + { DNS_KEYALG_ECCGOST, "ECCGOST", 0 }, \ { DNS_KEYALG_INDIRECT, "INDIRECT", 0 }, \ { DNS_KEYALG_PRIVATEDNS, "PRIVATEDNS", 0 }, \ { DNS_KEYALG_PRIVATEOID, "PRIVATEOID", 0 }, \ @@ -313,6 +319,21 @@ dns_secalg_totext(dns_secalg_t secalg, isc_buffer_t *target) { return (dns_mnemonic_totext(secalg, target, secalgs)); } +void +dns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size) { + isc_buffer_t b; + isc_region_t r; + isc_result_t result; + + REQUIRE(cp != NULL && size > 0); + isc_buffer_init(&b, cp, size - 1); + result = dns_secalg_totext(alg, &b); + isc_buffer_usedregion(&b, &r); + r.base[r.length] = 0; + if (result != ISC_R_SUCCESS) + r.base[0] = 0; +} + isc_result_t dns_secproto_fromtext(dns_secproto_t *secprotop, isc_textregion_t *source) { unsigned int value; diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c index daaa83a..c282b03 100644 --- a/lib/dns/rdata.c +++ b/lib/dns/rdata.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009, 2011 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdata.c,v 1.199.50.4 2011-01-13 04:48:21 tbox Exp $ */ +/* $Id: rdata.c,v 1.209 2011-01-13 04:59:25 tbox Exp $ */ /*! \file */ @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -275,23 +276,6 @@ dns_rdata_init(dns_rdata_t *rdata) { /* ISC_LIST_INIT(rdata->list); */ } -#if 1 -#define DNS_RDATA_INITIALIZED(rdata) \ - ((rdata)->data == NULL && (rdata)->length == 0 && \ - (rdata)->rdclass == 0 && (rdata)->type == 0 && (rdata)->flags == 0 && \ - !ISC_LINK_LINKED((rdata), link)) -#else -#ifdef ISC_LIST_CHECKINIT -#define DNS_RDATA_INITIALIZED(rdata) \ - (!ISC_LINK_LINKED((rdata), link)) -#else -#define DNS_RDATA_INITIALIZED(rdata) ISC_TRUE -#endif -#endif - -#define DNS_RDATA_VALIDFLAGS(rdata) \ - (((rdata)->flags & ~(DNS_RDATA_UPDATE|DNS_RDATA_OFFLINE)) == 0) - void dns_rdata_reset(dns_rdata_t *rdata) { @@ -365,6 +349,37 @@ dns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) { return (result); } +int +dns_rdata_casecompare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) { + int result = 0; + isc_boolean_t use_default = ISC_FALSE; + + REQUIRE(rdata1 != NULL); + REQUIRE(rdata2 != NULL); + REQUIRE(rdata1->data != NULL); + REQUIRE(rdata2->data != NULL); + REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1)); + REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2)); + + if (rdata1->rdclass != rdata2->rdclass) + return (rdata1->rdclass < rdata2->rdclass ? -1 : 1); + + if (rdata1->type != rdata2->type) + return (rdata1->type < rdata2->type ? -1 : 1); + + CASECOMPARESWITCH + + if (use_default) { + isc_region_t r1; + isc_region_t r2; + + dns_rdata_toregion(rdata1, &r1); + dns_rdata_toregion(rdata2, &r2); + result = isc_region_compare(&r1, &r2); + } + return (result); +} + /*** *** Conversions ***/ @@ -1772,3 +1787,93 @@ dns_rdatatype_isknown(dns_rdatatype_t type) { return (ISC_TRUE); return (ISC_FALSE); } + +void +dns_rdata_exists(dns_rdata_t *rdata, dns_rdatatype_t type) { + + REQUIRE(rdata != NULL); + REQUIRE(DNS_RDATA_INITIALIZED(rdata)); + + rdata->data = NULL; + rdata->length = 0; + rdata->flags = DNS_RDATA_UPDATE; + rdata->type = type; + rdata->rdclass = dns_rdataclass_any; +} + +void +dns_rdata_notexist(dns_rdata_t *rdata, dns_rdatatype_t type) { + + REQUIRE(rdata != NULL); + REQUIRE(DNS_RDATA_INITIALIZED(rdata)); + + rdata->data = NULL; + rdata->length = 0; + rdata->flags = DNS_RDATA_UPDATE; + rdata->type = type; + rdata->rdclass = dns_rdataclass_none; +} + +void +dns_rdata_deleterrset(dns_rdata_t *rdata, dns_rdatatype_t type) { + + REQUIRE(rdata != NULL); + REQUIRE(DNS_RDATA_INITIALIZED(rdata)); + + rdata->data = NULL; + rdata->length = 0; + rdata->flags = DNS_RDATA_UPDATE; + rdata->type = type; + rdata->rdclass = dns_rdataclass_any; +} + +void +dns_rdata_makedelete(dns_rdata_t *rdata) { + REQUIRE(rdata != NULL); + + rdata->rdclass = dns_rdataclass_none; +} + +const char * +dns_rdata_updateop(dns_rdata_t *rdata, dns_section_t section) { + + REQUIRE(rdata != NULL); + REQUIRE(DNS_RDATA_INITIALIZED(rdata)); + + switch (section) { + case DNS_SECTION_PREREQUISITE: + switch (rdata->rdclass) { + case dns_rdataclass_none: + switch (rdata->type) { + case dns_rdatatype_any: + return ("domain doesn't exist"); + default: + return ("rrset doesn't exist"); + } + case dns_rdataclass_any: + switch (rdata->type) { + case dns_rdatatype_any: + return ("domain exists"); + default: + return ("rrset exists (value independent)"); + } + default: + return ("rrset exists (value dependent)"); + } + case DNS_SECTION_UPDATE: + switch (rdata->rdclass) { + case dns_rdataclass_none: + return ("delete"); + case dns_rdataclass_any: + switch (rdata->type) { + case dns_rdatatype_any: + return ("delete all rrsets"); + default: + return ("delete rrset"); + } + default: + return ("add"); + } + } + return ("invalid"); +} diff --git a/lib/dns/rdata/any_255/tsig_250.c b/lib/dns/rdata/any_255/tsig_250.c index e698239..9763f6d 100644 --- a/lib/dns/rdata/any_255/tsig_250.c +++ b/lib/dns/rdata/any_255/tsig_250.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tsig_250.c,v 1.63 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: tsig_250.c,v 1.65 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Thu Mar 16 13:39:43 PST 2000 by gson */ @@ -594,4 +594,9 @@ checknames_any_tsig(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_any_tsig(ARGS_COMPARE) { + return (compare_any_tsig(rdata1, rdata2)); +} + #endif /* RDATA_ANY_255_TSIG_250_C */ diff --git a/lib/dns/rdata/ch_3/a_1.c b/lib/dns/rdata/ch_3/a_1.c index 156caac..2623f76 100644 --- a/lib/dns/rdata/ch_3/a_1.c +++ b/lib/dns/rdata/ch_3/a_1.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: a_1.c,v 1.6 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: a_1.c,v 1.8 2009-12-04 22:06:37 tbox Exp $ */ /* by Bjorn.Victor@it.uu.se, 2005-05-07 */ /* Based on generic/soa_6.c and generic/mx_15.c */ @@ -107,7 +107,7 @@ fromwire_ch_a(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); dns_name_init(&name, NULL); - + RETERR(dns_name_fromwire(&name, source, dctx, options, target)); isc_buffer_activeregion(source, &sregion); @@ -205,7 +205,7 @@ fromstruct_ch_a(ARGS_FROMSTRUCT) { dns_name_toregion(&a->ch_addr_dom, ®ion); RETERR(isc_buffer_copyregion(target, ®ion)); - + return (uint16_tobuffer(ntohs(a->ch_addr), target)); } @@ -313,4 +313,8 @@ checknames_ch_a(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_ch_a(ARGS_COMPARE) { + return (compare_ch_a(rdata1, rdata2)); +} #endif /* RDATA_CH_3_A_1_C */ diff --git a/lib/dns/rdata/generic/afsdb_18.c b/lib/dns/rdata/generic/afsdb_18.c index f82167be..bd1d1e0 100644 --- a/lib/dns/rdata/generic/afsdb_18.c +++ b/lib/dns/rdata/generic/afsdb_18.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: afsdb_18.c,v 1.47 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: afsdb_18.c,v 1.49 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Wed Mar 15 14:59:00 PST 2000 by explorer */ @@ -306,4 +306,8 @@ checknames_afsdb(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_afsdb(ARGS_COMPARE) { + return (compare_afsdb(rdata1, rdata2)); +} #endif /* RDATA_GENERIC_AFSDB_18_C */ diff --git a/lib/dns/rdata/generic/cert_37.c b/lib/dns/rdata/generic/cert_37.c index e0398d2..d06b4e6 100644 --- a/lib/dns/rdata/generic/cert_37.c +++ b/lib/dns/rdata/generic/cert_37.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cert_37.c,v 1.50 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: cert_37.c,v 1.52 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Wed Mar 15 21:14:32 EST 2000 by tale */ @@ -276,5 +276,9 @@ checknames_cert(ARGS_CHECKNAMES) { return (ISC_TRUE); } -#endif /* RDATA_GENERIC_CERT_37_C */ +static inline int +casecompare_cert(ARGS_COMPARE) { + return (compare_cert(rdata1, rdata2)); +} +#endif /* RDATA_GENERIC_CERT_37_C */ diff --git a/lib/dns/rdata/generic/cname_5.c b/lib/dns/rdata/generic/cname_5.c index f44d8c5..508bb20 100644 --- a/lib/dns/rdata/generic/cname_5.c +++ b/lib/dns/rdata/generic/cname_5.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cname_5.c,v 1.47 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: cname_5.c,v 1.49 2009-12-04 22:06:37 tbox Exp $ */ /* reviewed: Wed Mar 15 16:48:45 PST 2000 by brister */ @@ -229,4 +229,9 @@ checknames_cname(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_cname(ARGS_COMPARE) { + return (compare_cname(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_CNAME_5_C */ diff --git a/lib/dns/rdata/generic/dlv_32769.c b/lib/dns/rdata/generic/dlv_32769.c index 21d7abbb4..0f87433c 100644 --- a/lib/dns/rdata/generic/dlv_32769.c +++ b/lib/dns/rdata/generic/dlv_32769.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2006, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2006, 2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dlv_32769.c,v 1.6 2007-06-18 23:47:43 tbox Exp $ */ +/* $Id: dlv_32769.c,v 1.10 2010-12-23 23:47:08 tbox Exp $ */ /* draft-ietf-dnsext-delegation-signer-05.txt */ @@ -74,12 +74,20 @@ fromtext_dlv(ARGS_FROMTEXT) { /* * Digest. */ - if (c == DNS_DSDIGEST_SHA1) + switch (c) { + case DNS_DSDIGEST_SHA1: length = ISC_SHA1_DIGESTLENGTH; - else if (c == DNS_DSDIGEST_SHA256) + break; + case DNS_DSDIGEST_SHA256: length = ISC_SHA256_DIGESTLENGTH; - else + break; + case DNS_DSDIGEST_GOST: + length = ISC_GOST_DIGESTLENGTH; + break; + default: length = -1; + break; + } return (isc_hex_tobuffer(lexer, target, -1)); } @@ -144,7 +152,7 @@ fromwire_dlv(ARGS_FROMWIRE) { UNUSED(options); isc_buffer_activeregion(source, &sr); - + /* * Check digest lengths if we know them. */ @@ -152,7 +160,9 @@ fromwire_dlv(ARGS_FROMWIRE) { (sr.base[3] == DNS_DSDIGEST_SHA1 && sr.length < 4 + ISC_SHA1_DIGESTLENGTH) || (sr.base[3] == DNS_DSDIGEST_SHA256 && - sr.length < 4 + ISC_SHA256_DIGESTLENGTH)) + sr.length < 4 + ISC_SHA256_DIGESTLENGTH) || + (sr.base[3] == DNS_DSDIGEST_GOST && + sr.length < 4 + ISC_GOST_DIGESTLENGTH)) return (ISC_R_UNEXPECTEDEND); /* @@ -164,7 +174,9 @@ fromwire_dlv(ARGS_FROMWIRE) { sr.length = 4 + ISC_SHA1_DIGESTLENGTH; else if (sr.base[3] == DNS_DSDIGEST_SHA256) sr.length = 4 + ISC_SHA256_DIGESTLENGTH; - + else if (sr.base[3] == DNS_DSDIGEST_GOST) + sr.length = 4 + ISC_GOST_DIGESTLENGTH; + isc_buffer_forward(source, sr.length); return (mem_tobuffer(target, sr.base, sr.length)); } @@ -213,6 +225,9 @@ fromstruct_dlv(ARGS_FROMSTRUCT) { case DNS_DSDIGEST_SHA256: REQUIRE(dlv->length == ISC_SHA256_DIGESTLENGTH); break; + case DNS_DSDIGEST_GOST: + REQUIRE(dlv->length == ISC_GOST_DIGESTLENGTH); + break; } UNUSED(type); @@ -318,4 +333,9 @@ checknames_dlv(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_dlv(ARGS_COMPARE) { + return (compare_dlv(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_DLV_32769_C */ diff --git a/lib/dns/rdata/generic/dname_39.c b/lib/dns/rdata/generic/dname_39.c index e36702d..61356bf 100644 --- a/lib/dns/rdata/generic/dname_39.c +++ b/lib/dns/rdata/generic/dname_39.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dname_39.c,v 1.38 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: dname_39.c,v 1.40 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Wed Mar 15 16:52:38 PST 2000 by explorer */ @@ -230,4 +230,8 @@ checknames_dname(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_dname(ARGS_COMPARE) { + return (compare_dname(rdata1, rdata2)); +} #endif /* RDATA_GENERIC_DNAME_39_C */ diff --git a/lib/dns/rdata/generic/dnskey_48.c b/lib/dns/rdata/generic/dnskey_48.c index d526ca0..91fe9f8 100644 --- a/lib/dns/rdata/generic/dnskey_48.c +++ b/lib/dns/rdata/generic/dnskey_48.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnskey_48.c,v 1.8 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: dnskey_48.c,v 1.10 2009-12-04 22:06:37 tbox Exp $ */ /* * Reviewed: Wed Mar 15 16:47:10 PST 2000 by halley. @@ -76,6 +76,7 @@ totext_dnskey(ARGS_TOTEXT) { char buf[sizeof("64000")]; unsigned int flags; unsigned char algorithm; + char namebuf[DNS_NAME_FORMATSIZE]; REQUIRE(rdata->type == 48); REQUIRE(rdata->length != 0); @@ -105,6 +106,15 @@ totext_dnskey(ARGS_TOTEXT) { if ((flags & 0xc000) == 0xc000) return (ISC_R_SUCCESS); + if ((tctx->flags & DNS_STYLEFLAG_COMMENT) != 0 && + algorithm == DNS_KEYALG_PRIVATEDNS) { + dns_name_t name; + dns_name_init(&name, NULL); + dns_name_fromregion(&name, &sr); + dns_name_format(&name, namebuf, sizeof(namebuf)); + } else + namebuf[0] = 0; + /* key */ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) RETERR(str_totext(" (", target)); @@ -127,12 +137,18 @@ totext_dnskey(ARGS_TOTEXT) { dns_rdata_toregion(rdata, &tmpr); sprintf(buf, "%u", dst_region_computeid(&tmpr, algorithm)); RETERR(str_totext(buf, target)); + if (algorithm == DNS_KEYALG_PRIVATEDNS) { + RETERR(str_totext(tctx->linebreak, target)); + RETERR(str_totext("; alg = ", target)); + RETERR(str_totext(namebuf, target)); + } } return (ISC_R_SUCCESS); } static inline isc_result_t fromwire_dnskey(ARGS_FROMWIRE) { + unsigned char algorithm; isc_region_t sr; REQUIRE(type == 48); @@ -146,6 +162,18 @@ fromwire_dnskey(ARGS_FROMWIRE) { if (sr.length < 4) return (ISC_R_UNEXPECTEDEND); + algorithm = sr.base[3]; + RETERR(mem_tobuffer(target, sr.base, 4)); + isc_region_consume(&sr, 4); + isc_buffer_forward(source, 4); + + if (algorithm == DNS_KEYALG_PRIVATEDNS) { + dns_name_t name; + dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); + dns_name_init(&name, NULL); + RETERR(dns_name_fromwire(&name, source, dctx, options, target)); + } + isc_buffer_activeregion(source, &sr); isc_buffer_forward(source, sr.length); return (mem_tobuffer(target, sr.base, sr.length)); } @@ -309,4 +337,13 @@ checknames_dnskey(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_dnskey(ARGS_COMPARE) { + + /* + * Treat ALG 253 (private DNS) subtype name case sensistively. + */ + return (compare_dnskey(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_DNSKEY_48_C */ diff --git a/lib/dns/rdata/generic/ds_43.c b/lib/dns/rdata/generic/ds_43.c index fcaa69b..ee74ab67 100644 --- a/lib/dns/rdata/generic/ds_43.c +++ b/lib/dns/rdata/generic/ds_43.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ds_43.c,v 1.12 2007-06-18 23:47:43 tbox Exp $ */ +/* $Id: ds_43.c,v 1.16 2010-12-23 23:47:08 tbox Exp $ */ /* draft-ietf-dnsext-delegation-signer-05.txt */ @@ -74,12 +74,20 @@ fromtext_ds(ARGS_FROMTEXT) { /* * Digest. */ - if (c == DNS_DSDIGEST_SHA1) + switch (c) { + case DNS_DSDIGEST_SHA1: length = ISC_SHA1_DIGESTLENGTH; - else if (c == DNS_DSDIGEST_SHA256) + break; + case DNS_DSDIGEST_SHA256: length = ISC_SHA256_DIGESTLENGTH; - else + break; + case DNS_DSDIGEST_GOST: + length = ISC_GOST_DIGESTLENGTH; + break; + default: length = -1; + break; + } return (isc_hex_tobuffer(lexer, target, length)); } @@ -152,7 +160,9 @@ fromwire_ds(ARGS_FROMWIRE) { (sr.base[3] == DNS_DSDIGEST_SHA1 && sr.length < 4 + ISC_SHA1_DIGESTLENGTH) || (sr.base[3] == DNS_DSDIGEST_SHA256 && - sr.length < 4 + ISC_SHA256_DIGESTLENGTH)) + sr.length < 4 + ISC_SHA256_DIGESTLENGTH) || + (sr.base[3] == DNS_DSDIGEST_GOST && + sr.length < 4 + ISC_GOST_DIGESTLENGTH)) return (ISC_R_UNEXPECTEDEND); /* @@ -164,6 +174,8 @@ fromwire_ds(ARGS_FROMWIRE) { sr.length = 4 + ISC_SHA1_DIGESTLENGTH; else if (sr.base[3] == DNS_DSDIGEST_SHA256) sr.length = 4 + ISC_SHA256_DIGESTLENGTH; + else if (sr.base[3] == DNS_DSDIGEST_GOST) + sr.length = 4 + ISC_GOST_DIGESTLENGTH; isc_buffer_forward(source, sr.length); return (mem_tobuffer(target, sr.base, sr.length)); @@ -213,6 +225,9 @@ fromstruct_ds(ARGS_FROMSTRUCT) { case DNS_DSDIGEST_SHA256: REQUIRE(ds->length == ISC_SHA256_DIGESTLENGTH); break; + case DNS_DSDIGEST_GOST: + REQUIRE(ds->length == ISC_GOST_DIGESTLENGTH); + break; } UNUSED(type); @@ -318,4 +333,9 @@ checknames_ds(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_ds(ARGS_COMPARE) { + return (compare_ds(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_DS_43_C */ diff --git a/lib/dns/rdata/generic/gpos_27.c b/lib/dns/rdata/generic/gpos_27.c index 35fcc50..7a3992a 100644 --- a/lib/dns/rdata/generic/gpos_27.c +++ b/lib/dns/rdata/generic/gpos_27.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: gpos_27.c,v 1.41 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: gpos_27.c,v 1.43 2009-12-04 22:06:37 tbox Exp $ */ /* reviewed: Wed Mar 15 16:48:45 PST 2000 by brister */ @@ -249,4 +249,9 @@ checknames_gpos(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_gpos(ARGS_COMPARE) { + return (compare_gpos(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_GPOS_27_C */ diff --git a/lib/dns/rdata/generic/hinfo_13.c b/lib/dns/rdata/generic/hinfo_13.c index 7f31ab0..6b301e6 100644 --- a/lib/dns/rdata/generic/hinfo_13.c +++ b/lib/dns/rdata/generic/hinfo_13.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: hinfo_13.c,v 1.44 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: hinfo_13.c,v 1.46 2009-12-04 22:06:37 tbox Exp $ */ /* * Reviewed: Wed Mar 15 16:47:10 PST 2000 by halley. @@ -221,4 +221,8 @@ checknames_hinfo(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_hinfo(ARGS_COMPARE) { + return (compare_hinfo(rdata1, rdata2)); +} #endif /* RDATA_GENERIC_HINFO_13_C */ diff --git a/lib/dns/rdata/generic/hip_55.c b/lib/dns/rdata/generic/hip_55.c new file mode 100644 index 0000000..4cda9c6 --- /dev/null +++ b/lib/dns/rdata/generic/hip_55.c @@ -0,0 +1,506 @@ +/* + * Copyright (C) 2009, 2011 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: hip_55.c,v 1.8 2011-01-13 04:59:26 tbox Exp $ */ + +/* reviewed: TBC */ + +/* RFC 5205 */ + +#ifndef RDATA_GENERIC_HIP_5_C +#define RDATA_GENERIC_HIP_5_C + +#define RRTYPE_HIP_ATTRIBUTES (0) + +static inline isc_result_t +fromtext_hip(ARGS_FROMTEXT) { + isc_token_t token; + dns_name_t name; + isc_buffer_t buffer; + isc_buffer_t hit_len; + isc_buffer_t key_len; + unsigned char *start; + size_t len; + + REQUIRE(type == 55); + + UNUSED(type); + UNUSED(rdclass); + UNUSED(callbacks); + + /* + * Dummy HIT len. + */ + hit_len = *target; + RETERR(uint8_tobuffer(0, target)); + + /* + * Algorithm. + */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, + ISC_FALSE)); + if (token.value.as_ulong > 0xffU) + RETTOK(ISC_R_RANGE); + RETERR(uint8_tobuffer(token.value.as_ulong, target)); + + /* + * Dummy KEY len. + */ + key_len = *target; + RETERR(uint16_tobuffer(0, target)); + + /* + * HIT (base16). + */ + start = isc_buffer_used(target); + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(isc_hex_decodestring(DNS_AS_STR(token), target)); + + /* + * Fill in HIT len. + */ + len = (unsigned char *)isc_buffer_used(target) - start; + if (len > 0xffU) + RETTOK(ISC_R_RANGE); + RETERR(uint8_tobuffer(len, &hit_len)); + + /* + * Public key (base64). + */ + start = isc_buffer_used(target); + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(isc_base64_decodestring(DNS_AS_STR(token), target)); + + /* + * Fill in KEY len. + */ + len = (unsigned char *)isc_buffer_used(target) - start; + if (len > 0xffffU) + RETTOK(ISC_R_RANGE); + RETERR(uint16_tobuffer(len, &key_len)); + + /* + * Rendezvous Servers. + */ + dns_name_init(&name, NULL); + do { + RETERR(isc_lex_getmastertoken(lexer, &token, + isc_tokentype_string, + ISC_TRUE)); + if (token.type != isc_tokentype_string) + break; + buffer_fromregion(&buffer, &token.value.as_region); + origin = (origin != NULL) ? origin : dns_rootname; + RETTOK(dns_name_fromtext(&name, &buffer, origin, options, + target)); + } while (1); + + /* + * Let upper layer handle eol/eof. + */ + isc_lex_ungettoken(lexer, &token); + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +totext_hip(ARGS_TOTEXT) { + isc_region_t region; + dns_name_t name; + size_t length, key_len, hit_len; + unsigned char algorithm; + char buf[sizeof("225 ")]; + + REQUIRE(rdata->type == 55); + REQUIRE(rdata->length != 0); + + dns_rdata_toregion(rdata, ®ion); + + hit_len = uint8_fromregion(®ion); + isc_region_consume(®ion, 1); + + algorithm = uint8_fromregion(®ion); + isc_region_consume(®ion, 1); + + key_len = uint16_fromregion(®ion); + isc_region_consume(®ion, 2); + + if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) + RETERR(str_totext("( ", target)); + + /* + * Algorithm + */ + sprintf(buf, "%u ", algorithm); + RETERR(str_totext(buf, target)); + + /* + * HIT. + */ + INSIST(hit_len < region.length); + length = region.length; + region.length = hit_len; + RETERR(isc_hex_totext(®ion, 1, "", target)); + region.length = length - hit_len; + RETERR(str_totext(tctx->linebreak, target)); + + /* + * Public KEY. + */ + INSIST(key_len <= region.length); + length = region.length; + region.length = key_len; + RETERR(isc_base64_totext(®ion, 1, "", target)); + region.length = length - key_len; + RETERR(str_totext(tctx->linebreak, target)); + + /* + * Rendezvous Servers. + */ + dns_name_init(&name, NULL); + while (region.length > 0) { + dns_name_fromregion(&name, ®ion); + + RETERR(dns_name_totext(&name, ISC_FALSE, target)); + isc_region_consume(®ion, name.length); + if (region.length > 0) + RETERR(str_totext(tctx->linebreak, target)); + } + if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) + RETERR(str_totext(" )", target)); + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +fromwire_hip(ARGS_FROMWIRE) { + isc_region_t region, rr; + dns_name_t name; + isc_uint8_t hit_len; + isc_uint16_t key_len; + + REQUIRE(type == 55); + + UNUSED(type); + UNUSED(rdclass); + + isc_buffer_activeregion(source, ®ion); + if (region.length < 4U) + RETERR(DNS_R_FORMERR); + + rr = region; + hit_len = uint8_fromregion(®ion); + if (hit_len == 0) + RETERR(DNS_R_FORMERR); + isc_region_consume(®ion, 2); /* hit length + algorithm */ + key_len = uint16_fromregion(®ion); + if (key_len == 0) + RETERR(DNS_R_FORMERR); + isc_region_consume(®ion, 2); + if (region.length < (unsigned) (hit_len + key_len)) + RETERR(DNS_R_FORMERR); + + RETERR(mem_tobuffer(target, rr.base, 4 + hit_len + key_len)); + isc_buffer_forward(source, 4 + hit_len + key_len); + + dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); + while (isc_buffer_activelength(source) > 0) { + dns_name_init(&name, NULL); + RETERR(dns_name_fromwire(&name, source, dctx, options, target)); + } + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +towire_hip(ARGS_TOWIRE) { + isc_region_t region; + + REQUIRE(rdata->type == 55); + REQUIRE(rdata->length != 0); + + UNUSED(cctx); + + dns_rdata_toregion(rdata, ®ion); + return (mem_tobuffer(target, region.base, region.length)); +} + +static inline int +compare_hip(ARGS_COMPARE) { + isc_region_t region1; + isc_region_t region2; + + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->type == 55); + REQUIRE(rdata1->length != 0); + REQUIRE(rdata2->length != 0); + + dns_rdata_toregion(rdata1, ®ion1); + dns_rdata_toregion(rdata2, ®ion2); + return (isc_region_compare(®ion1, ®ion2)); +} + +static inline isc_result_t +fromstruct_hip(ARGS_FROMSTRUCT) { + dns_rdata_hip_t *hip = source; + dns_rdata_hip_t myhip; + isc_result_t result; + + REQUIRE(type == 55); + REQUIRE(source != NULL); + REQUIRE(hip->common.rdtype == type); + REQUIRE(hip->common.rdclass == rdclass); + REQUIRE(hip->hit_len > 0 && hip->hit != NULL); + REQUIRE(hip->key_len > 0 && hip->key != NULL); + REQUIRE((hip->servers == NULL && hip->servers_len == 0) || + (hip->servers != NULL && hip->servers_len != 0)); + + UNUSED(type); + UNUSED(rdclass); + + RETERR(uint8_tobuffer(hip->hit_len, target)); + RETERR(uint8_tobuffer(hip->algorithm, target)); + RETERR(uint16_tobuffer(hip->key_len, target)); + RETERR(mem_tobuffer(target, hip->hit, hip->hit_len)); + RETERR(mem_tobuffer(target, hip->key, hip->key_len)); + + myhip = *hip; + for (result = dns_rdata_hip_first(&myhip); + result == ISC_R_SUCCESS; + result = dns_rdata_hip_next(&myhip)) + /* empty */; + + return(mem_tobuffer(target, hip->servers, hip->servers_len)); +} + +static inline isc_result_t +tostruct_hip(ARGS_TOSTRUCT) { + isc_region_t region; + dns_rdata_hip_t *hip = target; + + REQUIRE(rdata->type == 55); + REQUIRE(target != NULL); + REQUIRE(rdata->length != 0); + + hip->common.rdclass = rdata->rdclass; + hip->common.rdtype = rdata->type; + ISC_LINK_INIT(&hip->common, link); + + dns_rdata_toregion(rdata, ®ion); + + hip->hit_len = uint8_fromregion(®ion); + isc_region_consume(®ion, 1); + + hip->algorithm = uint8_fromregion(®ion); + isc_region_consume(®ion, 1); + + hip->key_len = uint16_fromregion(®ion); + isc_region_consume(®ion, 2); + + hip->hit = hip->key = hip->servers = NULL; + + hip->hit = mem_maybedup(mctx, region.base, hip->hit_len); + if (hip->hit == NULL) + goto cleanup; + isc_region_consume(®ion, hip->hit_len); + + hip->key = mem_maybedup(mctx, region.base, hip->key_len); + if (hip->key == NULL) + goto cleanup; + isc_region_consume(®ion, hip->key_len); + + hip->servers_len = region.length; + if (hip->servers_len != 0) { + hip->servers = mem_maybedup(mctx, region.base, region.length); + if (hip->servers == NULL) + goto cleanup; + } + + hip->offset = hip->servers_len; + hip->mctx = mctx; + return (ISC_R_SUCCESS); + + cleanup: + if (hip->hit != NULL) + isc_mem_free(mctx, hip->hit); + if (hip->key != NULL) + isc_mem_free(mctx, hip->key); + if (hip->servers != NULL) + isc_mem_free(mctx, hip->servers); + return (ISC_R_NOMEMORY); + +} + +static inline void +freestruct_hip(ARGS_FREESTRUCT) { + dns_rdata_hip_t *hip = source; + + REQUIRE(source != NULL); + + if (hip->mctx == NULL) + return; + + isc_mem_free(hip->mctx, hip->hit); + isc_mem_free(hip->mctx, hip->key); + if (hip->servers != NULL) + isc_mem_free(hip->mctx, hip->servers); + hip->mctx = NULL; +} + +static inline isc_result_t +additionaldata_hip(ARGS_ADDLDATA) { + UNUSED(rdata); + UNUSED(add); + UNUSED(arg); + + REQUIRE(rdata->type == 55); + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +digest_hip(ARGS_DIGEST) { + isc_region_t r; + + REQUIRE(rdata->type == 55); + + dns_rdata_toregion(rdata, &r); + return ((digest)(arg, &r)); +} + +static inline isc_boolean_t +checkowner_hip(ARGS_CHECKOWNER) { + + REQUIRE(type == 55); + + UNUSED(name); + UNUSED(type); + UNUSED(rdclass); + UNUSED(wildcard); + + return (ISC_TRUE); +} + +static inline isc_boolean_t +checknames_hip(ARGS_CHECKNAMES) { + + REQUIRE(rdata->type == 55); + + UNUSED(rdata); + UNUSED(owner); + UNUSED(bad); + + return (ISC_TRUE); +} + +isc_result_t +dns_rdata_hip_first(dns_rdata_hip_t *hip) { + if (hip->servers_len == 0) + return (ISC_R_NOMORE); + hip->offset = 0; + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_rdata_hip_next(dns_rdata_hip_t *hip) { + isc_region_t region; + dns_name_t name; + + if (hip->offset >= hip->servers_len) + return (ISC_R_NOMORE); + + region.base = hip->servers + hip->offset; + region.length = hip->servers_len - hip->offset; + dns_name_init(&name, NULL); + dns_name_fromregion(&name, ®ion); + hip->offset += name.length; + INSIST(hip->offset <= hip->servers_len); + return (ISC_R_SUCCESS); +} + +void +dns_rdata_hip_current(dns_rdata_hip_t *hip, dns_name_t *name) { + isc_region_t region; + + REQUIRE(hip->offset < hip->servers_len); + + region.base = hip->servers + hip->offset; + region.length = hip->servers_len - hip->offset; + dns_name_fromregion(name, ®ion); + + INSIST(name->length + hip->offset <= hip->servers_len); +} + +static inline int +casecompare_hip(ARGS_COMPARE) { + isc_region_t r1; + isc_region_t r2; + dns_name_t name1; + dns_name_t name2; + int order; + isc_uint8_t hit_len; + isc_uint16_t key_len; + + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->type == 55); + REQUIRE(rdata1->length != 0); + REQUIRE(rdata2->length != 0); + + dns_rdata_toregion(rdata1, &r1); + dns_rdata_toregion(rdata2, &r2); + + INSIST(r1.length > 4); + INSIST(r2.length > 4); + r1.length = 4; + r2.length = 4; + order = isc_region_compare(&r1, &r2); + if (order != 0) + return (order); + + hit_len = uint8_fromregion(&r1); + isc_region_consume(&r1, 2); /* hit length + algorithm */ + key_len = uint16_fromregion(&r1); + + dns_rdata_toregion(rdata1, &r1); + dns_rdata_toregion(rdata2, &r2); + isc_region_consume(&r1, 4); + isc_region_consume(&r2, 4); + INSIST(r1.length >= (unsigned) (hit_len + key_len)); + INSIST(r2.length >= (unsigned) (hit_len + key_len)); + order = isc_region_compare(&r1, &r2); + if (order != 0) + return (order); + isc_region_consume(&r1, hit_len + key_len); + isc_region_consume(&r2, hit_len + key_len); + + dns_name_init(&name1, NULL); + dns_name_init(&name2, NULL); + while (r1.length != 0 && r2.length != 0) { + dns_name_fromregion(&name1, &r1); + dns_name_fromregion(&name2, &r2); + order = dns_name_rdatacompare(&name1, &name2); + if (order != 0) + return (order); + + isc_region_consume(&r1, name_length(&name1)); + isc_region_consume(&r2, name_length(&name2)); + } + return (isc_region_compare(&r1, &r2)); +} + +#endif /* RDATA_GENERIC_HIP_5_C */ diff --git a/lib/dns/rdata/generic/hip_55.h b/lib/dns/rdata/generic/hip_55.h new file mode 100644 index 0000000..79828ad --- /dev/null +++ b/lib/dns/rdata/generic/hip_55.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: hip_55.h,v 1.2 2009-02-26 06:09:19 marka Exp $ */ + +#ifndef GENERIC_HIP_5_H +#define GENERIC_HIP_5_H 1 + +/* RFC 5205 */ + +typedef struct dns_rdata_hip { + dns_rdatacommon_t common; + isc_mem_t * mctx; + unsigned char * hit; + unsigned char * key; + unsigned char * servers; + isc_uint8_t algorithm; + isc_uint8_t hit_len; + isc_uint16_t key_len; + isc_uint16_t servers_len; + /* Private */ + isc_uint16_t offset; +} dns_rdata_hip_t; + +isc_result_t +dns_rdata_hip_first(dns_rdata_hip_t *); + +isc_result_t +dns_rdata_hip_next(dns_rdata_hip_t *); + +void +dns_rdata_hip_current(dns_rdata_hip_t *, dns_name_t *); + +#endif /* GENERIC_HIP_5_H */ diff --git a/lib/dns/rdata/generic/ipseckey_45.c b/lib/dns/rdata/generic/ipseckey_45.c index f971d49..995a135 100644 --- a/lib/dns/rdata/generic/ipseckey_45.c +++ b/lib/dns/rdata/generic/ipseckey_45.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ipseckey_45.c,v 1.4.332.5 2011-01-13 04:48:23 tbox Exp $ */ +/* $Id: ipseckey_45.c,v 1.11 2011-01-13 04:59:26 tbox Exp $ */ #ifndef RDATA_GENERIC_IPSECKEY_45_C #define RDATA_GENERIC_IPSECKEY_45_C @@ -456,4 +456,43 @@ checknames_ipseckey(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_ipseckey(ARGS_COMPARE) { + isc_region_t region1; + isc_region_t region2; + dns_name_t name1; + dns_name_t name2; + int order; + + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->type == 45); + REQUIRE(rdata1->length >= 3); + REQUIRE(rdata2->length >= 3); + + dns_rdata_toregion(rdata1, ®ion1); + dns_rdata_toregion(rdata2, ®ion2); + + if (memcmp(region1.base, region2.base, 3) != 0 || region1.base[1] != 3) + return (isc_region_compare(®ion1, ®ion2)); + + dns_name_init(&name1, NULL); + dns_name_init(&name2, NULL); + + isc_region_consume(®ion1, 3); + isc_region_consume(®ion2, 3); + + dns_name_fromregion(&name1, ®ion1); + dns_name_fromregion(&name2, ®ion2); + + order = dns_name_rdatacompare(&name1, &name2); + if (order != 0) + return (order); + + isc_region_consume(®ion1, name_length(&name1)); + isc_region_consume(®ion2, name_length(&name2)); + + return (isc_region_compare(®ion1, ®ion2)); +} + #endif /* RDATA_GENERIC_IPSECKEY_45_C */ diff --git a/lib/dns/rdata/generic/isdn_20.c b/lib/dns/rdata/generic/isdn_20.c index a9e03b2c..b58776c 100644 --- a/lib/dns/rdata/generic/isdn_20.c +++ b/lib/dns/rdata/generic/isdn_20.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: isdn_20.c,v 1.38 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: isdn_20.c,v 1.40 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Wed Mar 15 16:53:11 PST 2000 by bwelling */ @@ -231,4 +231,9 @@ checknames_isdn(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_isdn(ARGS_COMPARE) { + return (compare_isdn(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_ISDN_20_C */ diff --git a/lib/dns/rdata/generic/key_25.c b/lib/dns/rdata/generic/key_25.c index acd314c..6fe27cb 100644 --- a/lib/dns/rdata/generic/key_25.c +++ b/lib/dns/rdata/generic/key_25.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: key_25.c,v 1.51 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: key_25.c,v 1.53 2009-12-04 22:06:37 tbox Exp $ */ /* * Reviewed: Wed Mar 15 16:47:10 PST 2000 by halley. @@ -76,6 +76,7 @@ totext_key(ARGS_TOTEXT) { char buf[sizeof("64000")]; unsigned int flags; unsigned char algorithm; + char namebuf[DNS_NAME_FORMATSIZE]; REQUIRE(rdata->type == 25); REQUIRE(rdata->length != 0); @@ -105,6 +106,15 @@ totext_key(ARGS_TOTEXT) { if ((flags & 0xc000) == 0xc000) return (ISC_R_SUCCESS); + if ((tctx->flags & DNS_STYLEFLAG_COMMENT) != 0 && + algorithm == DNS_KEYALG_PRIVATEDNS) { + dns_name_t name; + dns_name_init(&name, NULL); + dns_name_fromregion(&name, &sr); + dns_name_format(&name, namebuf, sizeof(namebuf)); + } else + namebuf[0] = 0; + /* key */ if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) RETERR(str_totext(" (", target)); @@ -127,12 +137,18 @@ totext_key(ARGS_TOTEXT) { dns_rdata_toregion(rdata, &tmpr); sprintf(buf, "%u", dst_region_computeid(&tmpr, algorithm)); RETERR(str_totext(buf, target)); + if (algorithm == DNS_KEYALG_PRIVATEDNS) { + RETERR(str_totext(tctx->linebreak, target)); + RETERR(str_totext("; alg = ", target)); + RETERR(str_totext(namebuf, target)); + } } return (ISC_R_SUCCESS); } static inline isc_result_t fromwire_key(ARGS_FROMWIRE) { + unsigned char algorithm; isc_region_t sr; REQUIRE(type == 25); @@ -146,6 +162,18 @@ fromwire_key(ARGS_FROMWIRE) { if (sr.length < 4) return (ISC_R_UNEXPECTEDEND); + algorithm = sr.base[3]; + RETERR(mem_tobuffer(target, sr.base, 4)); + isc_region_consume(&sr, 4); + isc_buffer_forward(source, 4); + + if (algorithm == DNS_KEYALG_PRIVATEDNS) { + dns_name_t name; + dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); + dns_name_init(&name, NULL); + RETERR(dns_name_fromwire(&name, source, dctx, options, target)); + } + isc_buffer_activeregion(source, &sr); isc_buffer_forward(source, sr.length); return (mem_tobuffer(target, sr.base, sr.length)); } @@ -309,4 +337,9 @@ checknames_key(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_key(ARGS_COMPARE) { + return (compare_key(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_KEY_25_C */ diff --git a/lib/dns/rdata/generic/keydata_65533.c b/lib/dns/rdata/generic/keydata_65533.c new file mode 100644 index 0000000..3636209 --- /dev/null +++ b/lib/dns/rdata/generic/keydata_65533.c @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: keydata_65533.c,v 1.3 2009-12-04 21:09:33 marka Exp $ */ + +#ifndef GENERIC_KEYDATA_65533_C +#define GENERIC_KEYDATA_65533_C 1 + +#include + +#define RRTYPE_KEYDATA_ATTRIBUTES (DNS_RDATATYPEATTR_DNSSEC) + +static inline isc_result_t +fromtext_keydata(ARGS_FROMTEXT) { + isc_token_t token; + dns_secalg_t alg; + dns_secproto_t proto; + dns_keyflags_t flags; + isc_uint32_t refresh, addhd, removehd; + + REQUIRE(type == 65533); + + UNUSED(type); + UNUSED(rdclass); + UNUSED(origin); + UNUSED(options); + UNUSED(callbacks); + + /* refresh timer */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &refresh)); + RETERR(uint32_tobuffer(refresh, target)); + + /* add hold-down */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &addhd)); + RETERR(uint32_tobuffer(addhd, target)); + + /* remove hold-down */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &removehd)); + RETERR(uint32_tobuffer(removehd, target)); + + /* flags */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_keyflags_fromtext(&flags, &token.value.as_textregion)); + RETERR(uint16_tobuffer(flags, target)); + + /* protocol */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_secproto_fromtext(&proto, &token.value.as_textregion)); + RETERR(mem_tobuffer(target, &proto, 1)); + + /* algorithm */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + RETTOK(dns_secalg_fromtext(&alg, &token.value.as_textregion)); + RETERR(mem_tobuffer(target, &alg, 1)); + + /* No Key? */ + if ((flags & 0xc000) == 0xc000) + return (ISC_R_SUCCESS); + + return (isc_base64_tobuffer(lexer, target, -1)); +} + +static inline isc_result_t +totext_keydata(ARGS_TOTEXT) { + isc_region_t sr; + char buf[sizeof("64000")]; + unsigned int flags; + unsigned char algorithm; + unsigned long when; + + REQUIRE(rdata->type == 65533); + REQUIRE(rdata->length != 0); + + dns_rdata_toregion(rdata, &sr); + + /* refresh timer */ + when = uint32_fromregion(&sr); + isc_region_consume(&sr, 4); + RETERR(dns_time32_totext(when, target)); + RETERR(str_totext(" ", target)); + + /* add hold-down */ + when = uint32_fromregion(&sr); + isc_region_consume(&sr, 4); + RETERR(dns_time32_totext(when, target)); + RETERR(str_totext(" ", target)); + + /* remove hold-down */ + when = uint32_fromregion(&sr); + isc_region_consume(&sr, 4); + RETERR(dns_time32_totext(when, target)); + RETERR(str_totext(" ", target)); + + /* flags */ + flags = uint16_fromregion(&sr); + isc_region_consume(&sr, 2); + sprintf(buf, "%u", flags); + RETERR(str_totext(buf, target)); + RETERR(str_totext(" ", target)); + + /* protocol */ + sprintf(buf, "%u", sr.base[0]); + isc_region_consume(&sr, 1); + RETERR(str_totext(buf, target)); + RETERR(str_totext(" ", target)); + + /* algorithm */ + algorithm = sr.base[0]; + sprintf(buf, "%u", algorithm); + isc_region_consume(&sr, 1); + RETERR(str_totext(buf, target)); + + /* No Key? */ + if ((flags & 0xc000) == 0xc000) + return (ISC_R_SUCCESS); + + /* key */ + if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) + RETERR(str_totext(" (", target)); + RETERR(str_totext(tctx->linebreak, target)); + RETERR(isc_base64_totext(&sr, tctx->width - 2, + tctx->linebreak, target)); + + if ((tctx->flags & DNS_STYLEFLAG_COMMENT) != 0) + RETERR(str_totext(tctx->linebreak, target)); + else if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) + RETERR(str_totext(" ", target)); + + if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) + RETERR(str_totext(")", target)); + + if ((tctx->flags & DNS_STYLEFLAG_COMMENT) != 0) { + isc_region_t tmpr; + + RETERR(str_totext(" ; key id = ", target)); + dns_rdata_toregion(rdata, &tmpr); + /* Skip over refresh, addhd, and removehd */ + isc_region_consume(&tmpr, 12); + sprintf(buf, "%u", dst_region_computeid(&tmpr, algorithm)); + RETERR(str_totext(buf, target)); + } + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +fromwire_keydata(ARGS_FROMWIRE) { + isc_region_t sr; + + REQUIRE(type == 65533); + + UNUSED(type); + UNUSED(rdclass); + UNUSED(dctx); + UNUSED(options); + + isc_buffer_activeregion(source, &sr); + if (sr.length < 4) + return (ISC_R_UNEXPECTEDEND); + + isc_buffer_forward(source, sr.length); + return (mem_tobuffer(target, sr.base, sr.length)); +} + +static inline isc_result_t +towire_keydata(ARGS_TOWIRE) { + isc_region_t sr; + + REQUIRE(rdata->type == 65533); + REQUIRE(rdata->length != 0); + + UNUSED(cctx); + + dns_rdata_toregion(rdata, &sr); + return (mem_tobuffer(target, sr.base, sr.length)); +} + +static inline int +compare_keydata(ARGS_COMPARE) { + isc_region_t r1; + isc_region_t r2; + + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->type == 65533); + REQUIRE(rdata1->length != 0); + REQUIRE(rdata2->length != 0); + + dns_rdata_toregion(rdata1, &r1); + dns_rdata_toregion(rdata2, &r2); + return (isc_region_compare(&r1, &r2)); +} + +static inline isc_result_t +fromstruct_keydata(ARGS_FROMSTRUCT) { + dns_rdata_keydata_t *keydata = source; + + REQUIRE(type == 65533); + REQUIRE(source != NULL); + REQUIRE(keydata->common.rdtype == type); + REQUIRE(keydata->common.rdclass == rdclass); + + UNUSED(type); + UNUSED(rdclass); + + /* Refresh timer */ + RETERR(uint32_tobuffer(keydata->refresh, target)); + + /* Add hold-down */ + RETERR(uint32_tobuffer(keydata->addhd, target)); + + /* Remove hold-down */ + RETERR(uint32_tobuffer(keydata->removehd, target)); + + /* Flags */ + RETERR(uint16_tobuffer(keydata->flags, target)); + + /* Protocol */ + RETERR(uint8_tobuffer(keydata->protocol, target)); + + /* Algorithm */ + RETERR(uint8_tobuffer(keydata->algorithm, target)); + + /* Data */ + return (mem_tobuffer(target, keydata->data, keydata->datalen)); +} + +static inline isc_result_t +tostruct_keydata(ARGS_TOSTRUCT) { + dns_rdata_keydata_t *keydata = target; + isc_region_t sr; + + REQUIRE(rdata->type == 65533); + REQUIRE(target != NULL); + REQUIRE(rdata->length != 0); + + keydata->common.rdclass = rdata->rdclass; + keydata->common.rdtype = rdata->type; + ISC_LINK_INIT(&keydata->common, link); + + dns_rdata_toregion(rdata, &sr); + + /* Refresh timer */ + if (sr.length < 4) + return (ISC_R_UNEXPECTEDEND); + keydata->refresh = uint32_fromregion(&sr); + isc_region_consume(&sr, 4); + + /* Add hold-down */ + if (sr.length < 4) + return (ISC_R_UNEXPECTEDEND); + keydata->addhd = uint32_fromregion(&sr); + isc_region_consume(&sr, 4); + + /* Remove hold-down */ + if (sr.length < 4) + return (ISC_R_UNEXPECTEDEND); + keydata->removehd = uint32_fromregion(&sr); + isc_region_consume(&sr, 4); + + /* Flags */ + if (sr.length < 2) + return (ISC_R_UNEXPECTEDEND); + keydata->flags = uint16_fromregion(&sr); + isc_region_consume(&sr, 2); + + /* Protocol */ + if (sr.length < 1) + return (ISC_R_UNEXPECTEDEND); + keydata->protocol = uint8_fromregion(&sr); + isc_region_consume(&sr, 1); + + /* Algorithm */ + if (sr.length < 1) + return (ISC_R_UNEXPECTEDEND); + keydata->algorithm = uint8_fromregion(&sr); + isc_region_consume(&sr, 1); + + /* Data */ + keydata->datalen = sr.length; + keydata->data = mem_maybedup(mctx, sr.base, keydata->datalen); + if (keydata->data == NULL) + return (ISC_R_NOMEMORY); + + keydata->mctx = mctx; + return (ISC_R_SUCCESS); +} + +static inline void +freestruct_keydata(ARGS_FREESTRUCT) { + dns_rdata_keydata_t *keydata = (dns_rdata_keydata_t *) source; + + REQUIRE(source != NULL); + REQUIRE(keydata->common.rdtype == 65533); + + if (keydata->mctx == NULL) + return; + + if (keydata->data != NULL) + isc_mem_free(keydata->mctx, keydata->data); + keydata->mctx = NULL; +} + +static inline isc_result_t +additionaldata_keydata(ARGS_ADDLDATA) { + REQUIRE(rdata->type == 65533); + + UNUSED(rdata); + UNUSED(add); + UNUSED(arg); + + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +digest_keydata(ARGS_DIGEST) { + isc_region_t r; + + REQUIRE(rdata->type == 65533); + + dns_rdata_toregion(rdata, &r); + + return ((digest)(arg, &r)); +} + +static inline isc_boolean_t +checkowner_keydata(ARGS_CHECKOWNER) { + + REQUIRE(type == 65533); + + UNUSED(name); + UNUSED(type); + UNUSED(rdclass); + UNUSED(wildcard); + + return (ISC_TRUE); +} + +static inline isc_boolean_t +checknames_keydata(ARGS_CHECKNAMES) { + + REQUIRE(rdata->type == 65533); + + UNUSED(rdata); + UNUSED(owner); + UNUSED(bad); + + return (ISC_TRUE); +} + +static inline int +casecompare_keydata(ARGS_COMPARE) { + return (compare_keydata(rdata1, rdata2)); +} + +#endif /* GENERIC_KEYDATA_65533_C */ diff --git a/lib/dns/rdata/generic/keydata_65533.h b/lib/dns/rdata/generic/keydata_65533.h new file mode 100644 index 0000000..21cb1ba --- /dev/null +++ b/lib/dns/rdata/generic/keydata_65533.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +#ifndef GENERIC_KEYDATA_65533_H +#define GENERIC_KEYDATA_65533_H 1 + +/* $Id: keydata_65533.h,v 1.2 2009-06-30 02:52:32 each Exp $ */ + +typedef struct dns_rdata_keydata { + dns_rdatacommon_t common; + isc_mem_t * mctx; + isc_uint32_t refresh; /* Timer for refreshing data */ + isc_uint32_t addhd; /* Hold-down timer for adding */ + isc_uint32_t removehd; /* Hold-down timer for removing */ + isc_uint16_t flags; /* Copy of DNSKEY_48 */ + isc_uint8_t protocol; + isc_uint8_t algorithm; + isc_uint16_t datalen; + unsigned char * data; +} dns_rdata_keydata_t; + +#endif /* GENERIC_KEYDATA_65533_H */ diff --git a/lib/dns/rdata/generic/loc_29.c b/lib/dns/rdata/generic/loc_29.c index a5efb01..62d5cd0 100644 --- a/lib/dns/rdata/generic/loc_29.c +++ b/lib/dns/rdata/generic/loc_29.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: loc_29.c,v 1.45.332.4 2009-02-17 05:54:12 marka Exp $ */ +/* $Id: loc_29.c,v 1.50 2009-12-04 21:09:33 marka Exp $ */ /* Reviewed: Wed Mar 15 18:13:09 PST 2000 by explorer */ @@ -796,4 +796,9 @@ checknames_loc(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_loc(ARGS_COMPARE) { + return (compare_loc(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_LOC_29_C */ diff --git a/lib/dns/rdata/generic/mb_7.c b/lib/dns/rdata/generic/mb_7.c index c47365a..7a4af1c 100644 --- a/lib/dns/rdata/generic/mb_7.c +++ b/lib/dns/rdata/generic/mb_7.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mb_7.c,v 1.45 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: mb_7.c,v 1.47 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Wed Mar 15 17:31:26 PST 2000 by bwelling */ @@ -69,7 +69,7 @@ totext_mb(ARGS_TOTEXT) { static inline isc_result_t fromwire_mb(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; REQUIRE(type == 7); @@ -78,8 +78,8 @@ fromwire_mb(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); - dns_name_init(&name, NULL); - return (dns_name_fromwire(&name, source, dctx, options, target)); + dns_name_init(&name, NULL); + return (dns_name_fromwire(&name, source, dctx, options, target)); } static inline isc_result_t @@ -231,4 +231,9 @@ checknames_mb(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_mb(ARGS_COMPARE) { + return (compare_mb(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_MB_7_C */ diff --git a/lib/dns/rdata/generic/md_3.c b/lib/dns/rdata/generic/md_3.c index 269f9be..ee06274 100644 --- a/lib/dns/rdata/generic/md_3.c +++ b/lib/dns/rdata/generic/md_3.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: md_3.c,v 1.47 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: md_3.c,v 1.49 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Wed Mar 15 17:48:20 PST 2000 by bwelling */ @@ -69,7 +69,7 @@ totext_md(ARGS_TOTEXT) { static inline isc_result_t fromwire_md(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; REQUIRE(type == 3); @@ -78,8 +78,8 @@ fromwire_md(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); - dns_name_init(&name, NULL); - return (dns_name_fromwire(&name, source, dctx, options, target)); + dns_name_init(&name, NULL); + return (dns_name_fromwire(&name, source, dctx, options, target)); } static inline isc_result_t @@ -233,4 +233,9 @@ checknames_md(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_md(ARGS_COMPARE) { + return (compare_md(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_MD_3_C */ diff --git a/lib/dns/rdata/generic/mf_4.c b/lib/dns/rdata/generic/mf_4.c index 9223384..d14bf6c 100644 --- a/lib/dns/rdata/generic/mf_4.c +++ b/lib/dns/rdata/generic/mf_4.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mf_4.c,v 1.45 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: mf_4.c,v 1.47 2009-12-04 22:06:37 tbox Exp $ */ /* reviewed: Wed Mar 15 17:47:33 PST 2000 by brister */ @@ -69,7 +69,7 @@ totext_mf(ARGS_TOTEXT) { static inline isc_result_t fromwire_mf(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; REQUIRE(type == 4); @@ -78,8 +78,8 @@ fromwire_mf(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); - dns_name_init(&name, NULL); - return (dns_name_fromwire(&name, source, dctx, options, target)); + dns_name_init(&name, NULL); + return (dns_name_fromwire(&name, source, dctx, options, target)); } static inline isc_result_t @@ -232,4 +232,9 @@ checknames_mf(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_mf(ARGS_COMPARE) { + return (compare_mf(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_MF_4_C */ diff --git a/lib/dns/rdata/generic/mg_8.c b/lib/dns/rdata/generic/mg_8.c index ba7630c..c1d553a 100644 --- a/lib/dns/rdata/generic/mg_8.c +++ b/lib/dns/rdata/generic/mg_8.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mg_8.c,v 1.43 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: mg_8.c,v 1.45 2009-12-04 22:06:37 tbox Exp $ */ /* reviewed: Wed Mar 15 17:49:21 PST 2000 by brister */ @@ -69,7 +69,7 @@ totext_mg(ARGS_TOTEXT) { static inline isc_result_t fromwire_mg(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; REQUIRE(type == 8); @@ -78,8 +78,8 @@ fromwire_mg(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); - dns_name_init(&name, NULL); - return (dns_name_fromwire(&name, source, dctx, options, target)); + dns_name_init(&name, NULL); + return (dns_name_fromwire(&name, source, dctx, options, target)); } static inline isc_result_t @@ -227,4 +227,9 @@ checknames_mg(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_mg(ARGS_COMPARE) { + return (compare_mg(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_MG_8_C */ diff --git a/lib/dns/rdata/generic/minfo_14.c b/lib/dns/rdata/generic/minfo_14.c index 6848a4e..881e624 100644 --- a/lib/dns/rdata/generic/minfo_14.c +++ b/lib/dns/rdata/generic/minfo_14.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: minfo_14.c,v 1.45 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: minfo_14.c,v 1.47 2009-12-04 22:06:37 tbox Exp $ */ /* reviewed: Wed Mar 15 17:45:32 PST 2000 by brister */ @@ -93,8 +93,8 @@ totext_minfo(ARGS_TOTEXT) { static inline isc_result_t fromwire_minfo(ARGS_FROMWIRE) { - dns_name_t rmail; - dns_name_t email; + dns_name_t rmail; + dns_name_t email; REQUIRE(type == 14); @@ -103,11 +103,11 @@ fromwire_minfo(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); - dns_name_init(&rmail, NULL); - dns_name_init(&email, NULL); + dns_name_init(&rmail, NULL); + dns_name_init(&email, NULL); - RETERR(dns_name_fromwire(&rmail, source, dctx, options, target)); - return (dns_name_fromwire(&email, source, dctx, options, target)); + RETERR(dns_name_fromwire(&rmail, source, dctx, options, target)); + return (dns_name_fromwire(&email, source, dctx, options, target)); } static inline isc_result_t @@ -321,4 +321,9 @@ checknames_minfo(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_minfo(ARGS_COMPARE) { + return (compare_minfo(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_MINFO_14_C */ diff --git a/lib/dns/rdata/generic/mr_9.c b/lib/dns/rdata/generic/mr_9.c index a480bd4..6c02108 100644 --- a/lib/dns/rdata/generic/mr_9.c +++ b/lib/dns/rdata/generic/mr_9.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mr_9.c,v 1.42 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: mr_9.c,v 1.44 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Wed Mar 15 21:30:35 EST 2000 by tale */ @@ -69,7 +69,7 @@ totext_mr(ARGS_TOTEXT) { static inline isc_result_t fromwire_mr(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; REQUIRE(type == 9); @@ -78,8 +78,8 @@ fromwire_mr(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); - dns_name_init(&name, NULL); - return (dns_name_fromwire(&name, source, dctx, options, target)); + dns_name_init(&name, NULL); + return (dns_name_fromwire(&name, source, dctx, options, target)); } static inline isc_result_t @@ -228,4 +228,9 @@ checknames_mr(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_mr(ARGS_COMPARE) { + return (compare_mr(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_MR_9_C */ diff --git a/lib/dns/rdata/generic/mx_15.c b/lib/dns/rdata/generic/mx_15.c index b7b43f3..0d8e6cd 100644 --- a/lib/dns/rdata/generic/mx_15.c +++ b/lib/dns/rdata/generic/mx_15.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mx_15.c,v 1.56 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: mx_15.c,v 1.58 2009-12-04 22:06:37 tbox Exp $ */ /* reviewed: Wed Mar 15 18:05:46 PST 2000 by brister */ @@ -120,7 +120,7 @@ totext_mx(ARGS_TOTEXT) { static inline isc_result_t fromwire_mx(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; isc_region_t sregion; REQUIRE(type == 15); @@ -130,7 +130,7 @@ fromwire_mx(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); - dns_name_init(&name, NULL); + dns_name_init(&name, NULL); isc_buffer_activeregion(source, &sregion); if (sregion.length < 2) @@ -316,4 +316,9 @@ checknames_mx(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_mx(ARGS_COMPARE) { + return (compare_mx(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_MX_15_C */ diff --git a/lib/dns/rdata/generic/ns_2.c b/lib/dns/rdata/generic/ns_2.c index 14e0c9d..f3df004 100644 --- a/lib/dns/rdata/generic/ns_2.c +++ b/lib/dns/rdata/generic/ns_2.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ns_2.c,v 1.46 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: ns_2.c,v 1.48 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Wed Mar 15 18:15:00 PST 2000 by bwelling */ @@ -77,7 +77,7 @@ totext_ns(ARGS_TOTEXT) { static inline isc_result_t fromwire_ns(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; REQUIRE(type == 2); @@ -86,8 +86,8 @@ fromwire_ns(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); - dns_name_init(&name, NULL); - return (dns_name_fromwire(&name, source, dctx, options, target)); + dns_name_init(&name, NULL); + return (dns_name_fromwire(&name, source, dctx, options, target)); } static inline isc_result_t @@ -248,4 +248,9 @@ checknames_ns(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_ns(ARGS_COMPARE) { + return (compare_ns(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_NS_2_C */ diff --git a/lib/dns/rdata/generic/nsec3_50.c b/lib/dns/rdata/generic/nsec3_50.c index 890af1a..d21b009 100644 --- a/lib/dns/rdata/generic/nsec3_50.c +++ b/lib/dns/rdata/generic/nsec3_50.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsec3_50.c,v 1.4.48.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: nsec3_50.c,v 1.7 2009-12-04 21:09:34 marka Exp $ */ /* * Copyright (C) 2004 Nominet, Ltd. @@ -478,4 +478,9 @@ checknames_nsec3(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_nsec3(ARGS_COMPARE) { + return (compare_nsec3(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_NSEC3_50_C */ diff --git a/lib/dns/rdata/generic/nsec3param_51.c b/lib/dns/rdata/generic/nsec3param_51.c index 1457015..01beb3c 100644 --- a/lib/dns/rdata/generic/nsec3param_51.c +++ b/lib/dns/rdata/generic/nsec3param_51.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsec3param_51.c,v 1.4.48.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: nsec3param_51.c,v 1.7 2009-12-04 21:09:34 marka Exp $ */ /* * Copyright (C) 2004 Nominet, Ltd. @@ -311,4 +311,9 @@ checknames_nsec3param(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_nsec3param(ARGS_COMPARE) { + return (compare_nsec3param(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_NSEC3PARAM_51_C */ diff --git a/lib/dns/rdata/generic/nsec_47.c b/lib/dns/rdata/generic/nsec_47.c index ace1035..5807d5f 100644 --- a/lib/dns/rdata/generic/nsec_47.c +++ b/lib/dns/rdata/generic/nsec_47.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007, 2008, 2011 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007-2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsec_47.c,v 1.11.82.2 2011-01-13 04:48:23 tbox Exp $ */ +/* $Id: nsec_47.c,v 1.15 2011-01-13 04:59:26 tbox Exp $ */ /* reviewed: Wed Mar 15 18:21:15 PST 2000 by brister */ @@ -361,4 +361,36 @@ checknames_nsec(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_nsec(ARGS_COMPARE) { + isc_region_t region1; + isc_region_t region2; + dns_name_t name1; + dns_name_t name2; + int order; + + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->type == 47); + REQUIRE(rdata1->length != 0); + REQUIRE(rdata2->length != 0); + + dns_name_init(&name1, NULL); + dns_name_init(&name2, NULL); + + dns_rdata_toregion(rdata1, ®ion1); + dns_rdata_toregion(rdata2, ®ion2); + + dns_name_fromregion(&name1, ®ion1); + dns_name_fromregion(&name2, ®ion2); + + order = dns_name_rdatacompare(&name1, &name2); + if (order != 0) + return (order); + + isc_region_consume(®ion1, name_length(&name1)); + isc_region_consume(®ion2, name_length(&name2)); + + return (isc_region_compare(®ion1, ®ion2)); +} #endif /* RDATA_GENERIC_NSEC_47_C */ diff --git a/lib/dns/rdata/generic/null_10.c b/lib/dns/rdata/generic/null_10.c index 06a8877..e6d9b9a 100644 --- a/lib/dns/rdata/generic/null_10.c +++ b/lib/dns/rdata/generic/null_10.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: null_10.c,v 1.42 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: null_10.c,v 1.44 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Thu Mar 16 13:57:50 PST 2000 by explorer */ @@ -189,4 +189,9 @@ checknames_null(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_null(ARGS_COMPARE) { + return (compare_null(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_NULL_10_C */ diff --git a/lib/dns/rdata/generic/nxt_30.c b/lib/dns/rdata/generic/nxt_30.c index 362e6fc..44ded55 100644 --- a/lib/dns/rdata/generic/nxt_30.c +++ b/lib/dns/rdata/generic/nxt_30.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nxt_30.c,v 1.63 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: nxt_30.c,v 1.65 2009-12-04 22:06:37 tbox Exp $ */ /* reviewed: Wed Mar 15 18:21:15 PST 2000 by brister */ @@ -326,4 +326,8 @@ checknames_nxt(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_nxt(ARGS_COMPARE) { + return (compare_nxt(rdata1, rdata2)); +} #endif /* RDATA_GENERIC_NXT_30_C */ diff --git a/lib/dns/rdata/generic/opt_41.c b/lib/dns/rdata/generic/opt_41.c index 506f4a3..695057d 100644 --- a/lib/dns/rdata/generic/opt_41.c +++ b/lib/dns/rdata/generic/opt_41.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: opt_41.c,v 1.33 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: opt_41.c,v 1.35 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Thu Mar 16 14:06:44 PST 2000 by gson */ @@ -277,4 +277,9 @@ checknames_opt(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_opt(ARGS_COMPARE) { + return (compare_opt(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_OPT_41_C */ diff --git a/lib/dns/rdata/generic/proforma.c b/lib/dns/rdata/generic/proforma.c index c3db196..0efc197 100644 --- a/lib/dns/rdata/generic/proforma.c +++ b/lib/dns/rdata/generic/proforma.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: proforma.c,v 1.36 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: proforma.c,v 1.38 2009-12-04 22:06:37 tbox Exp $ */ #ifndef RDATA_GENERIC_#_#_C #define RDATA_GENERIC_#_#_C @@ -170,4 +170,21 @@ checknames_#(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_#(ARGS_COMPARE) { + isc_region_t r1; + isc_region_t r2; + + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->type == #); + REQUIRE(rdata1->rdclass == #); + REQUIRE(rdata1->length != 0); /* XXX */ + REQUIRE(rdata2->length != 0); /* XXX */ + + dns_rdata_toregion(rdata1, &r1); + dns_rdata_toregion(rdata2, &r2); + return (isc_region_compare(&r1, &r2)); +} + #endif /* RDATA_GENERIC_#_#_C */ diff --git a/lib/dns/rdata/generic/ptr_12.c b/lib/dns/rdata/generic/ptr_12.c index 8e718cd..0ed648f 100644 --- a/lib/dns/rdata/generic/ptr_12.c +++ b/lib/dns/rdata/generic/ptr_12.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ptr_12.c,v 1.43 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: ptr_12.c,v 1.45 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Thu Mar 16 14:05:12 PST 2000 by explorer */ @@ -79,7 +79,7 @@ totext_ptr(ARGS_TOTEXT) { static inline isc_result_t fromwire_ptr(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; REQUIRE(type == 12); @@ -88,8 +88,8 @@ fromwire_ptr(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); - dns_name_init(&name, NULL); - return (dns_name_fromwire(&name, source, dctx, options, target)); + dns_name_init(&name, NULL); + return (dns_name_fromwire(&name, source, dctx, options, target)); } static inline isc_result_t @@ -288,4 +288,8 @@ checknames_ptr(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_ptr(ARGS_COMPARE) { + return (compare_ptr(rdata1, rdata2)); +} #endif /* RDATA_GENERIC_PTR_12_C */ diff --git a/lib/dns/rdata/generic/rp_17.c b/lib/dns/rdata/generic/rp_17.c index 19d7b35..2865e2f 100644 --- a/lib/dns/rdata/generic/rp_17.c +++ b/lib/dns/rdata/generic/rp_17.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rp_17.c,v 1.42 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: rp_17.c,v 1.44 2009-12-04 22:06:37 tbox Exp $ */ /* RFC1183 */ @@ -93,8 +93,8 @@ totext_rp(ARGS_TOTEXT) { static inline isc_result_t fromwire_rp(ARGS_FROMWIRE) { - dns_name_t rmail; - dns_name_t email; + dns_name_t rmail; + dns_name_t email; REQUIRE(type == 17); @@ -103,11 +103,11 @@ fromwire_rp(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); - dns_name_init(&rmail, NULL); - dns_name_init(&email, NULL); + dns_name_init(&rmail, NULL); + dns_name_init(&email, NULL); - RETERR(dns_name_fromwire(&rmail, source, dctx, options, target)); - return (dns_name_fromwire(&email, source, dctx, options, target)); + RETERR(dns_name_fromwire(&rmail, source, dctx, options, target)); + return (dns_name_fromwire(&email, source, dctx, options, target)); } static inline isc_result_t @@ -311,4 +311,8 @@ checknames_rp(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_rp(ARGS_COMPARE) { + return (compare_rp(rdata1, rdata2)); +} #endif /* RDATA_GENERIC_RP_17_C */ diff --git a/lib/dns/rdata/generic/rrsig_46.c b/lib/dns/rdata/generic/rrsig_46.c index bcbb05b..1fa7d07 100644 --- a/lib/dns/rdata/generic/rrsig_46.c +++ b/lib/dns/rdata/generic/rrsig_46.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2011 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rrsig_46.c,v 1.10.332.2 2011-01-13 04:48:23 tbox Exp $ */ +/* $Id: rrsig_46.c,v 1.14 2011-01-13 04:59:26 tbox Exp $ */ /* Reviewed: Fri Mar 17 09:05:02 PST 2000 by gson */ @@ -544,4 +544,47 @@ checknames_rrsig(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_rrsig(ARGS_COMPARE) { + isc_region_t r1; + isc_region_t r2; + dns_name_t name1; + dns_name_t name2; + int order; + + REQUIRE(rdata1->type == rdata2->type); + REQUIRE(rdata1->rdclass == rdata2->rdclass); + REQUIRE(rdata1->type == 46); + REQUIRE(rdata1->length != 0); + REQUIRE(rdata2->length != 0); + + dns_rdata_toregion(rdata1, &r1); + dns_rdata_toregion(rdata2, &r2); + + INSIST(r1.length > 18); + INSIST(r2.length > 18); + r1.length = 18; + r2.length = 18; + order = isc_region_compare(&r1, &r2); + if (order != 0) + return (order); + + dns_name_init(&name1, NULL); + dns_name_init(&name2, NULL); + dns_rdata_toregion(rdata1, &r1); + dns_rdata_toregion(rdata2, &r2); + isc_region_consume(&r1, 18); + isc_region_consume(&r2, 18); + dns_name_fromregion(&name1, &r1); + dns_name_fromregion(&name2, &r2); + order = dns_name_rdatacompare(&name1, &name2); + if (order != 0) + return (order); + + isc_region_consume(&r1, name_length(&name1)); + isc_region_consume(&r2, name_length(&name2)); + + return (isc_region_compare(&r1, &r2)); +} + #endif /* RDATA_GENERIC_RRSIG_46_C */ diff --git a/lib/dns/rdata/generic/rt_21.c b/lib/dns/rdata/generic/rt_21.c index 48323c7..efd51e2 100644 --- a/lib/dns/rdata/generic/rt_21.c +++ b/lib/dns/rdata/generic/rt_21.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rt_21.c,v 1.46 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: rt_21.c,v 1.48 2009-12-04 22:06:37 tbox Exp $ */ /* reviewed: Thu Mar 16 15:02:31 PST 2000 by brister */ @@ -90,7 +90,7 @@ totext_rt(ARGS_TOTEXT) { static inline isc_result_t fromwire_rt(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; isc_region_t sregion; isc_region_t tregion; @@ -101,7 +101,7 @@ fromwire_rt(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); - dns_name_init(&name, NULL); + dns_name_init(&name, NULL); isc_buffer_activeregion(source, &sregion); isc_buffer_availableregion(target, &tregion); @@ -308,4 +308,9 @@ checknames_rt(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_rt(ARGS_COMPARE) { + return (compare_rt(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_RT_21_C */ diff --git a/lib/dns/rdata/generic/sig_24.c b/lib/dns/rdata/generic/sig_24.c index 3010b8e..6366309 100644 --- a/lib/dns/rdata/generic/sig_24.c +++ b/lib/dns/rdata/generic/sig_24.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sig_24.c,v 1.66 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: sig_24.c,v 1.68 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Fri Mar 17 09:05:02 PST 2000 by gson */ @@ -575,4 +575,8 @@ checknames_sig(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_sig(ARGS_COMPARE) { + return (compare_sig(rdata1, rdata2)); +} #endif /* RDATA_GENERIC_SIG_24_C */ diff --git a/lib/dns/rdata/generic/soa_6.c b/lib/dns/rdata/generic/soa_6.c index d3fdf41..34361a8 100644 --- a/lib/dns/rdata/generic/soa_6.c +++ b/lib/dns/rdata/generic/soa_6.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: soa_6.c,v 1.61.332.2 2009-02-16 23:47:15 tbox Exp $ */ +/* $Id: soa_6.c,v 1.64 2009-12-04 21:09:34 marka Exp $ */ /* Reviewed: Thu Mar 16 15:18:32 PST 2000 by explorer */ @@ -441,4 +441,9 @@ checknames_soa(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_soa(ARGS_COMPARE) { + return (compare_soa(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_SOA_6_C */ diff --git a/lib/dns/rdata/generic/spf_99.c b/lib/dns/rdata/generic/spf_99.c index b1ad062..0f8ba5f 100644 --- a/lib/dns/rdata/generic/spf_99.c +++ b/lib/dns/rdata/generic/spf_99.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: spf_99.c,v 1.4 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: spf_99.c,v 1.6 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Thu Mar 16 15:40:00 PST 2000 by bwelling */ @@ -235,4 +235,8 @@ checknames_spf(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_spf(ARGS_COMPARE) { + return (compare_spf(rdata1, rdata2)); +} #endif /* RDATA_GENERIC_SPF_99_C */ diff --git a/lib/dns/rdata/generic/sshfp_44.c b/lib/dns/rdata/generic/sshfp_44.c index 892c1ec..7b34451 100644 --- a/lib/dns/rdata/generic/sshfp_44.c +++ b/lib/dns/rdata/generic/sshfp_44.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2006, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2006, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sshfp_44.c,v 1.7 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: sshfp_44.c,v 1.9 2009-12-04 22:06:37 tbox Exp $ */ /* RFC 4255 */ @@ -259,4 +259,9 @@ checknames_sshfp(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_sshfp(ARGS_COMPARE) { + return (compare_sshfp(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_SSHFP_44_C */ diff --git a/lib/dns/rdata/generic/tkey_249.c b/lib/dns/rdata/generic/tkey_249.c index 6927c8d..64acc0f 100644 --- a/lib/dns/rdata/generic/tkey_249.c +++ b/lib/dns/rdata/generic/tkey_249.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: tkey_249.c,v 1.57 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: tkey_249.c,v 1.59 2009-12-04 22:06:37 tbox Exp $ */ /* * Reviewed: Thu Mar 16 17:35:30 PST 2000 by halley. @@ -552,4 +552,8 @@ checknames_tkey(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline isc_result_t +casecompare_tkey(ARGS_COMPARE) { + return (compare_tkey(rdata1, rdata2)); +} #endif /* RDATA_GENERIC_TKEY_249_C */ diff --git a/lib/dns/rdata/generic/txt_16.c b/lib/dns/rdata/generic/txt_16.c index fa14b86..e04e0f0 100644 --- a/lib/dns/rdata/generic/txt_16.c +++ b/lib/dns/rdata/generic/txt_16.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: txt_16.c,v 1.45 2008-02-15 23:46:51 tbox Exp $ */ +/* $Id: txt_16.c,v 1.47 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Thu Mar 16 15:40:00 PST 2000 by bwelling */ @@ -235,4 +235,9 @@ checknames_txt(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline isc_result_t +casecompare_txt(ARGS_COMPARE) { + return (compare_txt(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_TXT_16_C */ diff --git a/lib/dns/rdata/generic/unspec_103.c b/lib/dns/rdata/generic/unspec_103.c index ffd14d9..0ce9a90 100644 --- a/lib/dns/rdata/generic/unspec_103.c +++ b/lib/dns/rdata/generic/unspec_103.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: unspec_103.c,v 1.35 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: unspec_103.c,v 1.37 2009-12-04 22:06:37 tbox Exp $ */ #ifndef RDATA_GENERIC_UNSPEC_103_C #define RDATA_GENERIC_UNSPEC_103_C @@ -186,4 +186,9 @@ checknames_unspec(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_unspec(ARGS_COMPARE) { + return (compare_unspec(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_UNSPEC_103_C */ diff --git a/lib/dns/rdata/generic/x25_19.c b/lib/dns/rdata/generic/x25_19.c index 47aeb7f..f315b89 100644 --- a/lib/dns/rdata/generic/x25_19.c +++ b/lib/dns/rdata/generic/x25_19.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: x25_19.c,v 1.39 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: x25_19.c,v 1.41 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Thu Mar 16 16:15:57 PST 2000 by bwelling */ @@ -216,4 +216,9 @@ checknames_x25(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_x25(ARGS_COMPARE) { + return (compare_x25(rdata1, rdata2)); +} + #endif /* RDATA_GENERIC_X25_19_C */ diff --git a/lib/dns/rdata/hs_4/a_1.c b/lib/dns/rdata/hs_4/a_1.c index ae30719..6d02b79 100644 --- a/lib/dns/rdata/hs_4/a_1.c +++ b/lib/dns/rdata/hs_4/a_1.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: a_1.c,v 1.31 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: a_1.c,v 1.33 2009-12-04 22:06:37 tbox Exp $ */ /* reviewed: Thu Mar 16 15:58:36 PST 2000 by brister */ @@ -229,4 +229,9 @@ checknames_hs_a(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_hs_a(ARGS_COMPARE) { + return (compare_hs_a(rdata1, rdata2)); +} + #endif /* RDATA_HS_4_A_1_C */ diff --git a/lib/dns/rdata/in_1/a6_38.c b/lib/dns/rdata/in_1/a6_38.c index 450b74c..ec453b1 100644 --- a/lib/dns/rdata/in_1/a6_38.c +++ b/lib/dns/rdata/in_1/a6_38.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: a6_38.c,v 1.54 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: a6_38.c,v 1.56 2009-12-04 22:06:37 tbox Exp $ */ /* RFC2874 */ @@ -458,4 +458,9 @@ checknames_in_a6(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_in_a6(ARGS_COMPARE) { + return (compare_in_a6(rdata1, rdata2)); +} + #endif /* RDATA_IN_1_A6_38_C */ diff --git a/lib/dns/rdata/in_1/a_1.c b/lib/dns/rdata/in_1/a_1.c index 1181e44..b4c1e94 100644 --- a/lib/dns/rdata/in_1/a_1.c +++ b/lib/dns/rdata/in_1/a_1.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: a_1.c,v 1.53 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: a_1.c,v 1.55 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Thu Mar 16 16:52:50 PST 2000 by bwelling */ @@ -233,4 +233,9 @@ checknames_in_a(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_in_a(ARGS_COMPARE) { + return (compare_in_a(rdata1, rdata2)); +} + #endif /* RDATA_IN_1_A_1_C */ diff --git a/lib/dns/rdata/in_1/aaaa_28.c b/lib/dns/rdata/in_1/aaaa_28.c index 119131c..fe3954e 100644 --- a/lib/dns/rdata/in_1/aaaa_28.c +++ b/lib/dns/rdata/in_1/aaaa_28.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: aaaa_28.c,v 1.45 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: aaaa_28.c,v 1.47 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Thu Mar 16 16:52:50 PST 2000 by bwelling */ @@ -230,4 +230,8 @@ checknames_in_aaaa(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_in_aaaa(ARGS_COMPARE) { + return (compare_in_aaaa(rdata1, rdata2)); +} #endif /* RDATA_IN_1_AAAA_28_C */ diff --git a/lib/dns/rdata/in_1/apl_42.c b/lib/dns/rdata/in_1/apl_42.c index 70f6880..3f37880 100644 --- a/lib/dns/rdata/in_1/apl_42.c +++ b/lib/dns/rdata/in_1/apl_42.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: apl_42.c,v 1.14 2008-01-22 23:28:04 tbox Exp $ */ +/* $Id: apl_42.c,v 1.16 2009-12-04 22:06:37 tbox Exp $ */ /* RFC3123 */ @@ -450,4 +450,9 @@ checknames_in_apl(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_in_apl(ARGS_COMPARE) { + return (compare_in_apl(rdata1, rdata2)); +} + #endif /* RDATA_IN_1_APL_42_C */ diff --git a/lib/dns/rdata/in_1/dhcid_49.c b/lib/dns/rdata/in_1/dhcid_49.c index 5759a76d..9eca46f 100644 --- a/lib/dns/rdata/in_1/dhcid_49.c +++ b/lib/dns/rdata/in_1/dhcid_49.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2006, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dhcid_49.c,v 1.5 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: dhcid_49.c,v 1.7 2009-12-04 22:06:37 tbox Exp $ */ /* RFC 4701 */ @@ -51,7 +51,7 @@ totext_in_dhcid(ARGS_TOTEXT) { dns_rdata_toregion(rdata, &sr); if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) - RETERR(str_totext("( " /*)*/, target)); + RETERR(str_totext("( " /*)*/, target)); RETERR(isc_base64_totext(&sr, tctx->width - 2, tctx->linebreak, target)); if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { @@ -226,4 +226,9 @@ checknames_in_dhcid(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_in_dhcid(ARGS_COMPARE) { + return (compare_in_dhcid(rdata1, rdata2)); +} + #endif /* RDATA_IN_1_DHCID_49_C */ diff --git a/lib/dns/rdata/in_1/kx_36.c b/lib/dns/rdata/in_1/kx_36.c index 795844d..dfc103b 100644 --- a/lib/dns/rdata/in_1/kx_36.c +++ b/lib/dns/rdata/in_1/kx_36.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: kx_36.c,v 1.45 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: kx_36.c,v 1.47 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Thu Mar 16 17:24:54 PST 2000 by explorer */ @@ -85,7 +85,7 @@ totext_in_kx(ARGS_TOTEXT) { static inline isc_result_t fromwire_in_kx(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; isc_region_t sregion; REQUIRE(type == 36); @@ -96,7 +96,7 @@ fromwire_in_kx(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); - dns_name_init(&name, NULL); + dns_name_init(&name, NULL); isc_buffer_activeregion(source, &sregion); if (sregion.length < 2) @@ -285,4 +285,9 @@ checknames_in_kx(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_in_kx(ARGS_COMPARE) { + return (compare_in_kx(rdata1, rdata2)); +} + #endif /* RDATA_IN_1_KX_36_C */ diff --git a/lib/dns/rdata/in_1/naptr_35.c b/lib/dns/rdata/in_1/naptr_35.c index 51aadf7..3d09757 100644 --- a/lib/dns/rdata/in_1/naptr_35.c +++ b/lib/dns/rdata/in_1/naptr_35.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: naptr_35.c,v 1.53 2008-02-15 23:46:51 tbox Exp $ */ +/* $Id: naptr_35.c,v 1.56 2009-12-04 21:09:34 marka Exp $ */ /* Reviewed: Thu Mar 16 16:52:50 PST 2000 by bwelling */ @@ -25,12 +25,134 @@ #define RDATA_IN_1_NAPTR_35_C #define RRTYPE_NAPTR_ATTRIBUTES (0) +#ifdef HAVE_REGEX_H +#include +#endif + +/* + * Check the wire format of the Regexp field. + * Don't allow embeded NUL's. + */ +static inline isc_result_t +txt_valid_regex(const unsigned char *txt) { +#ifdef HAVE_REGEX_H + regex_t preg; + unsigned int regflags = REG_EXTENDED; + unsigned int nsub = 0; + char regex[256]; + char *cp; +#endif + isc_boolean_t flags = ISC_FALSE; + isc_boolean_t replace = ISC_FALSE; + unsigned char c; + unsigned char delim; + unsigned int len; + + len = *txt++; + if (len == 0U) + return (ISC_R_SUCCESS); + + delim = *txt++; + len--; + + /* + * Digits, backslash and flags can't be delimiters. + */ + switch (delim) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '\\': case 'i': case 0: + return (DNS_R_SYNTAX); + } + +#ifdef HAVE_REGEX_H + memset(&preg, 0, sizeof(preg)); + cp = regex; +#endif + + while (len-- > 0) { + c = *txt++; + if (c == 0) + return (DNS_R_SYNTAX); + if (c == delim && !replace) { + replace = ISC_TRUE; + continue; + } else if (c == delim && !flags) { + flags = ISC_TRUE; + continue; + } else if (c == delim) + return (DNS_R_SYNTAX); + /* + * Flags are not escaped. + */ + if (flags) { + switch (c) { + case 'i': +#ifdef HAVE_REGEX_H + regflags |= REG_ICASE; +#endif + continue; + default: + return (DNS_R_SYNTAX); + } + } +#ifdef HAVE_REGEX_H + if (!replace) + *cp++ = c; +#endif + if (c == '\\') { + if (len == 0) + return (DNS_R_SYNTAX); + c = *txt++; + if (c == 0) + return (DNS_R_SYNTAX); + len--; + if (replace) + switch (c) { + case '0': return (DNS_R_SYNTAX); +#ifdef HAVE_REGEX_H + case '1': if (nsub < 1) nsub = 1; break; + case '2': if (nsub < 2) nsub = 2; break; + case '3': if (nsub < 3) nsub = 3; break; + case '4': if (nsub < 4) nsub = 4; break; + case '5': if (nsub < 5) nsub = 5; break; + case '6': if (nsub < 6) nsub = 6; break; + case '7': if (nsub < 7) nsub = 7; break; + case '8': if (nsub < 8) nsub = 8; break; + case '9': if (nsub < 9) nsub = 9; break; +#endif + } +#ifdef HAVE_REGEX_H + if (!replace) + *cp++ = c; +#endif + } + } + if (!flags) + return (DNS_R_SYNTAX); +#ifdef HAVE_REGEX_H + *cp = '\0'; + if (regcomp(&preg, regex, regflags)) + return (DNS_R_SYNTAX); + /* + * Check that substitutions in the replacement string are consistant + * with the regular expression. + */ + if (preg.re_nsub < nsub) { + regfree(&preg); + return (DNS_R_SYNTAX); + } + regfree(&preg); +#endif + return (ISC_R_SUCCESS); +} static inline isc_result_t fromtext_in_naptr(ARGS_FROMTEXT) { isc_token_t token; dns_name_t name; isc_buffer_t buffer; + unsigned char *regex; REQUIRE(type == 35); REQUIRE(rdclass == 1); @@ -74,9 +196,11 @@ fromtext_in_naptr(ARGS_FROMTEXT) { /* * Regexp. */ + regex = isc_buffer_used(target); RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring, ISC_FALSE)); RETTOK(txt_fromtext(&token.value.as_textregion, target)); + RETTOK(txt_valid_regex(regex)); /* * Replacement. @@ -156,6 +280,7 @@ static inline isc_result_t fromwire_in_naptr(ARGS_FROMWIRE) { dns_name_t name; isc_region_t sr; + unsigned char *regex; REQUIRE(type == 35); REQUIRE(rdclass == 1); @@ -189,7 +314,9 @@ fromwire_in_naptr(ARGS_FROMWIRE) { /* * Regexp. */ + regex = isc_buffer_used(target); RETERR(txt_fromwire(source, target)); + RETERR(txt_valid_regex(regex)); /* * Replacement. @@ -575,4 +702,9 @@ checknames_in_naptr(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_in_naptr(ARGS_COMPARE) { + return (compare_in_naptr(rdata1, rdata2)); +} + #endif /* RDATA_IN_1_NAPTR_35_C */ diff --git a/lib/dns/rdata/in_1/nsap-ptr_23.c b/lib/dns/rdata/in_1/nsap-ptr_23.c index 615d24a..2554b07 100644 --- a/lib/dns/rdata/in_1/nsap-ptr_23.c +++ b/lib/dns/rdata/in_1/nsap-ptr_23.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsap-ptr_23.c,v 1.38 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: nsap-ptr_23.c,v 1.40 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Fri Mar 17 10:16:02 PST 2000 by gson */ @@ -73,7 +73,7 @@ totext_in_nsap_ptr(ARGS_TOTEXT) { static inline isc_result_t fromwire_in_nsap_ptr(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; REQUIRE(type == 23); REQUIRE(rdclass == 1); @@ -83,8 +83,8 @@ fromwire_in_nsap_ptr(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); - dns_name_init(&name, NULL); - return (dns_name_fromwire(&name, source, dctx, options, target)); + dns_name_init(&name, NULL); + return (dns_name_fromwire(&name, source, dctx, options, target)); } static inline isc_result_t @@ -242,4 +242,9 @@ checknames_in_nsap_ptr(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_in_nsap_ptr(ARGS_COMPARE) { + return (compare_in_nsap_ptr(rdata1, rdata2)); +} + #endif /* RDATA_IN_1_NSAP_PTR_23_C */ diff --git a/lib/dns/rdata/in_1/nsap_22.c b/lib/dns/rdata/in_1/nsap_22.c index 1aaf13f..4a56c75 100644 --- a/lib/dns/rdata/in_1/nsap_22.c +++ b/lib/dns/rdata/in_1/nsap_22.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsap_22.c,v 1.42 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: nsap_22.c,v 1.44 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Fri Mar 17 10:41:07 PST 2000 by gson */ @@ -252,4 +252,9 @@ checknames_in_nsap(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_in_nsap(ARGS_COMPARE) { + return (compare_in_nsap(rdata1, rdata2)); +} + #endif /* RDATA_IN_1_NSAP_22_C */ diff --git a/lib/dns/rdata/in_1/px_26.c b/lib/dns/rdata/in_1/px_26.c index 517b87c..50f68cd 100644 --- a/lib/dns/rdata/in_1/px_26.c +++ b/lib/dns/rdata/in_1/px_26.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: px_26.c,v 1.43 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: px_26.c,v 1.45 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Mon Mar 20 10:44:27 PST 2000 */ @@ -115,7 +115,7 @@ totext_in_px(ARGS_TOTEXT) { static inline isc_result_t fromwire_in_px(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; isc_region_t sregion; REQUIRE(type == 26); @@ -126,7 +126,7 @@ fromwire_in_px(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); - dns_name_init(&name, NULL); + dns_name_init(&name, NULL); /* * Preference. @@ -371,4 +371,9 @@ checknames_in_px(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_in_px(ARGS_COMPARE) { + return (compare_in_px(rdata1, rdata2)); +} + #endif /* RDATA_IN_1_PX_26_C */ diff --git a/lib/dns/rdata/in_1/srv_33.c b/lib/dns/rdata/in_1/srv_33.c index ac9e577..3dfd13e 100644 --- a/lib/dns/rdata/in_1/srv_33.c +++ b/lib/dns/rdata/in_1/srv_33.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: srv_33.c,v 1.45 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: srv_33.c,v 1.47 2009-12-04 22:06:37 tbox Exp $ */ /* Reviewed: Fri Mar 17 13:01:00 PST 2000 by bwelling */ @@ -140,7 +140,7 @@ totext_in_srv(ARGS_TOTEXT) { static inline isc_result_t fromwire_in_srv(ARGS_FROMWIRE) { - dns_name_t name; + dns_name_t name; isc_region_t sr; REQUIRE(type == 33); @@ -151,7 +151,7 @@ fromwire_in_srv(ARGS_FROMWIRE) { dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); - dns_name_init(&name, NULL); + dns_name_init(&name, NULL); /* * Priority, weight, port. @@ -370,4 +370,9 @@ checknames_in_srv(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_in_srv(ARGS_COMPARE) { + return (compare_in_srv(rdata1, rdata2)); +} + #endif /* RDATA_IN_1_SRV_33_C */ diff --git a/lib/dns/rdata/in_1/wks_11.c b/lib/dns/rdata/in_1/wks_11.c index b7d5057..29983ec 100644 --- a/lib/dns/rdata/in_1/wks_11.c +++ b/lib/dns/rdata/in_1/wks_11.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: wks_11.c,v 1.54.332.2 2009-02-16 23:47:15 tbox Exp $ */ +/* $Id: wks_11.c,v 1.57 2009-12-04 21:09:34 marka Exp $ */ /* Reviewed: Fri Mar 17 15:01:49 PST 2000 by explorer */ @@ -348,4 +348,9 @@ checknames_in_wks(ARGS_CHECKNAMES) { return (ISC_TRUE); } +static inline int +casecompare_in_wks(ARGS_COMPARE) { + return (compare_in_wks(rdata1, rdata2)); +} + #endif /* RDATA_IN_1_WKS_11_C */ diff --git a/lib/dns/rdatalist.c b/lib/dns/rdatalist.c index e8178a7..d30aff9 100644 --- a/lib/dns/rdatalist.c +++ b/lib/dns/rdatalist.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdatalist.c,v 1.36.50.2 2010-02-25 10:56:41 tbox Exp $ */ +/* $Id: rdatalist.c,v 1.40 2010-11-16 05:38:31 marka Exp $ */ /*! \file */ diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c index 672e001..fdd7669 100644 --- a/lib/dns/rdataset.c +++ b/lib/dns/rdataset.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdataset.c,v 1.82.50.4.6.3 2011-06-21 20:13:23 each Exp $ */ +/* $Id: rdataset.c,v 1.86.220.3 2011-06-21 20:15:53 each Exp $ */ /*! \file */ diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index d1a02a0..932f8de 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdataslab.c,v 1.48.50.4 2010-02-25 10:56:41 tbox Exp $ */ +/* $Id: rdataslab.c,v 1.52.148.1.2.1 2011-06-02 23:47:35 tbox Exp $ */ /*! \file */ @@ -144,21 +144,25 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, nalloc = dns_rdataset_count(rdataset); nitems = nalloc; - if (nitems == 0) + if (nitems == 0 && rdataset->type != 0) return (ISC_R_FAILURE); if (nalloc > 0xffff) return (ISC_R_NOSPACE); - x = isc_mem_get(mctx, nalloc * sizeof(struct xrdata)); - if (x == NULL) - return (ISC_R_NOMEMORY); + + if (nalloc != 0) { + x = isc_mem_get(mctx, nalloc * sizeof(struct xrdata)); + if (x == NULL) + return (ISC_R_NOMEMORY); + } else + x = NULL; /* * Save all of the rdata members into an array. */ result = dns_rdataset_first(rdataset); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) goto free_rdatas; for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) { INSIST(result == ISC_R_SUCCESS); @@ -223,11 +227,14 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, /* * Don't forget the last item! */ + if (nalloc != 0) { #if DNS_RDATASET_FIXED - buflen += (8 + x[i-1].rdata.length); + buflen += (8 + x[i-1].rdata.length); #else - buflen += (2 + x[i-1].rdata.length); + buflen += (2 + x[i-1].rdata.length); #endif + } + /* * Provide space to store the per RR meta data. */ @@ -316,7 +323,8 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, result = ISC_R_SUCCESS; free_rdatas: - isc_mem_put(mctx, x, nalloc * sizeof(struct xrdata)); + if (x != NULL) + isc_mem_put(mctx, x, nalloc * sizeof(struct xrdata)); return (result); } diff --git a/lib/dns/request.c b/lib/dns/request.c index c1cd235..b5d6248 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: request.c,v 1.82.72.2 2009-01-18 23:47:40 tbox Exp $ */ +/* $Id: request.c,v 1.87 2010-03-04 23:50:34 tbox Exp $ */ /*! \file */ @@ -449,7 +449,8 @@ req_send(dns_request_t *request, isc_task_t *task, isc_sockaddr_t *address) { } static isc_result_t -new_request(isc_mem_t *mctx, dns_request_t **requestp) { +new_request(isc_mem_t *mctx, dns_request_t **requestp) +{ dns_request_t *request; request = isc_mem_get(mctx, sizeof(*request)); @@ -1058,6 +1059,9 @@ req_render(dns_message_t *message, isc_buffer_t **bufferp, return (result); cleanup_cctx = ISC_TRUE; + if ((options & DNS_REQUESTOPT_CASE) != 0) + dns_compress_setsensitive(&cctx, ISC_TRUE); + /* * Render message. */ diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index f60eee9..6d9ab70 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.c,v 1.384.14.30.4.1 2011-06-21 20:13:23 each Exp $ */ +/* $Id: resolver.c,v 1.428.6.5.2.1 2011-06-21 20:15:53 each Exp $ */ /*! \file */ @@ -105,6 +105,14 @@ #define QTRACE(m) #endif +#ifndef DEFAULT_QUERY_TIMEOUT +#define DEFAULT_QUERY_TIMEOUT 30 /* The default time in seconds for the whole query to live. */ +#endif + +#ifndef MAXIMUM_QUERY_TIMEOUT +#define MAXIMUM_QUERY_TIMEOUT 30 /* The maximum time in seconds for the whole query to live. */ +#endif + /*% * Maximum EDNS0 input packet size. */ @@ -273,6 +281,8 @@ struct fetchctx { unsigned int findfail; unsigned int valfail; isc_boolean_t timeout; + dns_adbaddrinfo_t *addrinfo; + isc_sockaddr_t *client; }; #define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!') @@ -384,6 +394,7 @@ struct dns_resolver { unsigned int spillatmin; isc_timer_t * spillattimer; isc_boolean_t zero_no_soa_ttl; + unsigned int query_timeout; /* Locked by lock. */ unsigned int references; @@ -1035,6 +1046,7 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result, int line) { ISC_LIST_UNLINK(fctx->events, event, ev_link); task = event->ev_sender; event->ev_sender = fctx; + event->vresult = fctx->vresult; if (!HAVE_ANSWER(fctx)) event->result = result; @@ -1742,9 +1754,8 @@ resquery_send(resquery_t *query) { if ((query->options & DNS_FETCHOPT_NOVALIDATE) != 0) { fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD; } else if (res->view->enablevalidation) { - result = dns_keytable_issecuredomain(res->view->secroots, - &fctx->name, - &secure_domain); + result = dns_view_issecuredomain(res->view, &fctx->name, + &secure_domain); if (result != ISC_R_SUCCESS) secure_domain = ISC_FALSE; if (res->view->dlv != NULL) @@ -2285,7 +2296,7 @@ add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason, char code[64]; isc_buffer_t b; isc_sockaddr_t *sa; - const char *sep1, *sep2; + const char *spc = ""; isc_sockaddr_t *address = &addrinfo->sockaddr; if (reason == DNS_R_LAME) @@ -2331,18 +2342,14 @@ add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason, isc_buffer_init(&b, code, sizeof(code) - 1); dns_rcode_totext(fctx->rmessage->rcode, &b); code[isc_buffer_usedlength(&b)] = '\0'; - sep1 = "("; - sep2 = ") "; + spc = " "; } else if (reason == DNS_R_UNEXPECTEDOPCODE) { isc_buffer_init(&b, code, sizeof(code) - 1); dns_opcode_totext((dns_opcode_t)fctx->rmessage->opcode, &b); code[isc_buffer_usedlength(&b)] = '\0'; - sep1 = "("; - sep2 = ") "; + spc = " "; } else { code[0] = '\0'; - sep1 = ""; - sep2 = ""; } dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf)); @@ -2350,83 +2357,19 @@ add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason, isc_sockaddr_format(address, addrbuf, sizeof(addrbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, - "%s %s%s%sresolving '%s/%s/%s': %s", - dns_result_totext(reason), sep1, code, sep2, + "error (%s%s%s) resolving '%s/%s/%s': %s", + dns_result_totext(reason), spc, code, namebuf, typebuf, classbuf, addrbuf); } /* - * Return 'bits' bits of random entropy from fctx->rand_buf, - * refreshing it by calling isc_random_get() whenever the requested - * number of bits is greater than the number in the buffer. - */ -static inline isc_uint32_t -random_bits(fetchctx_t *fctx, isc_uint32_t bits) { - isc_uint32_t ret = 0; - - REQUIRE(VALID_FCTX(fctx)); - REQUIRE(bits <= 32); - if (bits == 0) - return (0); - - if (bits >= fctx->rand_bits) { - /* if rand_bits == 0, this is unnecessary but harmless */ - bits -= fctx->rand_bits; - ret = fctx->rand_buf << bits; - - /* refresh random buffer now */ - isc_random_get(&fctx->rand_buf); - fctx->rand_bits = sizeof(fctx->rand_buf) * CHAR_BIT; - } - - if (bits > 0) { - isc_uint32_t mask = 0xffffffff; - if (bits < 32) { - mask = (1 << bits) - 1; - } - - ret |= fctx->rand_buf & mask; - fctx->rand_buf >>= bits; - fctx->rand_bits -= bits; - } - - return (ret); -} - -/* - * Add some random jitter to a server's RTT value so that the - * order of queries will be unpredictable. - * - * RTT values of servers which have been tried are fuzzed by 128 ms. - * Servers that haven't been tried yet have their RTT set to a random - * value between 0 ms and 7 ms; they should get to go first, but in - * unpredictable order. - */ -static inline void -randomize_srtt(fetchctx_t *fctx, dns_adbaddrinfo_t *ai) { - if (TRIED(ai)) { - ai->srtt >>= 10; /* convert to milliseconds, near enough */ - ai->srtt |= (ai->srtt & 0x80) | random_bits(fctx, 7); - ai->srtt <<= 10; /* now back to microseconds */ - } else - ai->srtt = random_bits(fctx, 3) << 10; -} - -/* - * Sort addrinfo list by RTT (with random jitter) + * Sort addrinfo list by RTT. */ static void -sort_adbfind(fetchctx_t *fctx, dns_adbfind_t *find) { +sort_adbfind(dns_adbfind_t *find) { dns_adbaddrinfo_t *best, *curr; dns_adbaddrinfolist_t sorted; - /* Add jitter to SRTT values */ - curr = ISC_LIST_HEAD(find->list); - while (curr != NULL) { - randomize_srtt(fctx, curr); - curr = ISC_LIST_NEXT(curr, publink); - } - /* Lame N^2 bubble sort. */ ISC_LIST_INIT(sorted); while (!ISC_LIST_EMPTY(find->list)) { @@ -2444,19 +2387,19 @@ sort_adbfind(fetchctx_t *fctx, dns_adbfind_t *find) { } /* - * Sort a list of finds by server RTT (with random jitter) + * Sort a list of finds by server RTT. */ static void -sort_finds(fetchctx_t *fctx, dns_adbfindlist_t *findlist) { +sort_finds(dns_adbfindlist_t *findlist) { dns_adbfind_t *best, *curr; dns_adbfindlist_t sorted; dns_adbaddrinfo_t *addrinfo, *bestaddrinfo; - /* Sort each find's addrinfo list by SRTT (after adding jitter) */ + /* Sort each find's addrinfo list by SRTT. */ for (curr = ISC_LIST_HEAD(*findlist); curr != NULL; curr = ISC_LIST_NEXT(curr, publink)) - sort_adbfind(fctx, curr); + sort_adbfind(curr); /* Lame N^2 bubble sort. */ ISC_LIST_INIT(sorted); @@ -2841,8 +2784,8 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) { * We've found some addresses. We might still be looking * for more addresses. */ - sort_finds(fctx, &fctx->finds); - sort_finds(fctx, &fctx->altfinds); + sort_finds(&fctx->finds); + sort_finds(&fctx->altfinds); result = ISC_R_SUCCESS; } @@ -3471,6 +3414,7 @@ fctx_join(fetchctx_t *fctx, isc_task_t *task, isc_sockaddr_t *client, else ISC_LIST_APPEND(fctx->events, event, ev_link); fctx->references++; + fctx->client = client; fetch->magic = DNS_FETCH_MAGIC; fetch->private = fctx; @@ -3569,6 +3513,8 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, fctx->rand_buf = 0; fctx->rand_bits = 0; fctx->timeout = ISC_FALSE; + fctx->addrinfo = NULL; + fctx->client = NULL; dns_name_init(&fctx->nsname, NULL); fctx->nsfetch = NULL; @@ -3658,7 +3604,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, /* * Compute an expiration time for the entire fetch. */ - isc_interval_set(&interval, 30, 0); /* XXXRTH constant */ + isc_interval_set(&interval, res->query_timeout, 0); iresult = isc_time_nowplusinterval(&fctx->expires, &interval); if (iresult != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, @@ -3800,6 +3746,33 @@ log_lame(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo) { namebuf, domainbuf, addrbuf); } +static inline void +log_formerr(fetchctx_t *fctx, const char *format, ...) { + char nsbuf[ISC_SOCKADDR_FORMATSIZE]; + char clbuf[ISC_SOCKADDR_FORMATSIZE]; + const char *clmsg = ""; + char msgbuf[2048]; + va_list args; + + va_start(args, format); + vsnprintf(msgbuf, sizeof(msgbuf), format, args); + va_end(args); + + isc_sockaddr_format(&fctx->addrinfo->sockaddr, nsbuf, sizeof(nsbuf)); + + if (fctx->client != NULL) { + clmsg = " for client "; + isc_sockaddr_format(fctx->client, clbuf, sizeof(clbuf)); + } else { + clbuf[0] = '\0'; + } + + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, + DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE, + "DNS format error from %s resolving %s%s%s: %s", + nsbuf, fctx->info, clmsg, clbuf, msgbuf); +} + static inline isc_result_t same_question(fetchctx_t *fctx) { isc_result_t result; @@ -3814,8 +3787,10 @@ same_question(fetchctx_t *fctx) { /* * XXXRTH Currently we support only one question. */ - if (message->counts[DNS_SECTION_QUESTION] != 1) + if (message->counts[DNS_SECTION_QUESTION] != 1) { + log_formerr(fctx, "too many questions"); return (DNS_R_FORMERR); + } result = dns_message_firstname(message, DNS_SECTION_QUESTION); if (result != ISC_R_SUCCESS) @@ -3825,10 +3800,21 @@ same_question(fetchctx_t *fctx) { rdataset = ISC_LIST_HEAD(name->list); INSIST(rdataset != NULL); INSIST(ISC_LIST_NEXT(rdataset, link) == NULL); + if (fctx->type != rdataset->type || fctx->res->rdclass != rdataset->rdclass || - !dns_name_equal(&fctx->name, name)) + !dns_name_equal(&fctx->name, name)) { + char namebuf[DNS_NAME_FORMATSIZE]; + char class[DNS_RDATACLASS_FORMATSIZE]; + char type[DNS_RDATATYPE_FORMATSIZE]; + + dns_name_format(name, namebuf, sizeof(namebuf)); + dns_rdataclass_format(rdataset->rdclass, class, sizeof(class)); + dns_rdatatype_format(rdataset->type, type, sizeof(type)); + log_formerr(fctx, "question section mismatch: got %s/%s/%s", + namebuf, class, type); return (DNS_R_FORMERR); + } return (ISC_R_SUCCESS); } @@ -3958,6 +3944,7 @@ validated(isc_task_t *task, isc_event_t *event) { REQUIRE(!ISC_LIST_EMPTY(fctx->validators)); vevent = (dns_validatorevent_t *)event; + fctx->vresult = vevent->result; FCTXTRACE("received validation completion event"); @@ -4331,8 +4318,8 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, * Is DNSSEC validation required for this name? */ if (res->view->enablevalidation) { - result = dns_keytable_issecuredomain(res->view->secroots, name, - &secure_domain); + result = dns_view_issecuredomain(res->view, name, + &secure_domain); if (result != ISC_R_SUCCESS) return (result); @@ -4804,8 +4791,8 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, * Is DNSSEC validation required for this name? */ if (fctx->res->view->enablevalidation) { - result = dns_keytable_issecuredomain(res->view->secroots, name, - &secure_domain); + result = dns_view_issecuredomain(res->view, name, + &secure_domain); if (result != ISC_R_SUCCESS) return (result); @@ -4949,7 +4936,9 @@ mark_related(dns_name_t *name, dns_rdataset_t *rdataset, } static isc_result_t -check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) { +check_section(void *arg, dns_name_t *addname, dns_rdatatype_t type, + dns_section_t section) +{ fetchctx_t *fctx = arg; isc_result_t result; dns_name_t *name; @@ -4960,15 +4949,19 @@ check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) { REQUIRE(VALID_FCTX(fctx)); +#if CHECK_FOR_GLUE_IN_ANSWER + if (section == DNS_SECTION_ANSWER && type != dns_rdatatype_a) + return (ISC_R_SUCCESS); +#endif + if (GLUING(fctx)) gluing = ISC_TRUE; else gluing = ISC_FALSE; name = NULL; rdataset = NULL; - result = dns_message_findname(fctx->rmessage, DNS_SECTION_ADDITIONAL, - addname, dns_rdatatype_any, 0, &name, - NULL); + result = dns_message_findname(fctx->rmessage, section, addname, + dns_rdatatype_any, 0, &name, NULL); if (result == ISC_R_SUCCESS) { external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); if (type == dns_rdatatype_a) { @@ -5006,6 +4999,21 @@ check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) { return (ISC_R_SUCCESS); } +static isc_result_t +check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) { + return (check_section(arg, addname, type, DNS_SECTION_ADDITIONAL)); +} + +#ifndef CHECK_FOR_GLUE_IN_ANSWER +#define CHECK_FOR_GLUE_IN_ANSWER 0 +#endif +#if CHECK_FOR_GLUE_IN_ANSWER +static isc_result_t +check_answer(void *arg, dns_name_t *addname, dns_rdatatype_t type) { + return (check_section(arg, addname, type, DNS_SECTION_ANSWER)); +} +#endif + static void chase_additional(fetchctx_t *fctx) { isc_boolean_t rescan; @@ -5062,8 +5070,8 @@ cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) { } static inline isc_result_t -dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, dns_name_t *oname, - dns_fixedname_t *fixeddname) +dname_target(fetchctx_t *fctx, dns_rdataset_t *rdataset, dns_name_t *qname, + dns_name_t *oname, dns_fixedname_t *fixeddname) { isc_result_t result; dns_rdata_t rdata = DNS_RDATA_INIT; @@ -5076,7 +5084,6 @@ dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, dns_name_t *oname, /* * Get the target name of the DNAME. */ - result = dns_rdataset_first(rdataset); if (result != ISC_R_SUCCESS) return (result); @@ -5090,7 +5097,14 @@ dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, dns_name_t *oname, */ namereln = dns_name_fullcompare(qname, oname, &order, &nlabels); if (namereln != dns_namereln_subdomain) { + char qbuf[DNS_NAME_FORMATSIZE]; + char obuf[DNS_NAME_FORMATSIZE]; + dns_rdata_freestruct(&dname); + dns_name_format(qname, qbuf, sizeof(qbuf)); + dns_name_format(oname, obuf, sizeof(obuf)); + log_formerr(fctx, "unrelated DNAME in answer: " + "%s is not in %s", qbuf, obuf); return (DNS_R_FORMERR); } dns_fixedname_init(&prefix); @@ -5103,16 +5117,147 @@ dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, dns_name_t *oname, return (result); } +static isc_boolean_t +is_answeraddress_allowed(dns_view_t *view, dns_name_t *name, + dns_rdataset_t *rdataset) +{ + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + struct in_addr ina; + struct in6_addr in6a; + isc_netaddr_t netaddr; + char addrbuf[ISC_NETADDR_FORMATSIZE]; + char namebuf[DNS_NAME_FORMATSIZE]; + char classbuf[64]; + char typebuf[64]; + int match; + + /* By default, we allow any addresses. */ + if (view->denyansweracl == NULL) + return (ISC_TRUE); + + /* + * If the owner name matches one in the exclusion list, either exactly + * or partially, allow it. + */ + if (view->answeracl_exclude != NULL) { + dns_rbtnode_t *node = NULL; + + result = dns_rbt_findnode(view->answeracl_exclude, name, NULL, + &node, NULL, 0, NULL, NULL); + + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) + return (ISC_TRUE); + } + + /* + * Otherwise, search the filter list for a match for each address + * record. If a match is found, the address should be filtered, + * so should the entire answer. + */ + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); + if (rdataset->type == dns_rdatatype_a) { + INSIST(rdata.length == sizeof(ina.s_addr)); + memcpy(&ina.s_addr, rdata.data, sizeof(ina.s_addr)); + isc_netaddr_fromin(&netaddr, &ina); + } else { + INSIST(rdata.length == sizeof(in6a.s6_addr)); + memcpy(in6a.s6_addr, rdata.data, sizeof(in6a.s6_addr)); + isc_netaddr_fromin6(&netaddr, &in6a); + } + + result = dns_acl_match(&netaddr, NULL, view->denyansweracl, + &view->aclenv, &match, NULL); + + if (result == ISC_R_SUCCESS && match > 0) { + isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf)); + dns_name_format(name, namebuf, sizeof(namebuf)); + dns_rdatatype_format(rdataset->type, typebuf, + sizeof(typebuf)); + dns_rdataclass_format(rdataset->rdclass, classbuf, + sizeof(classbuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, + DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE, + "answer address %s denied for %s/%s/%s", + addrbuf, namebuf, typebuf, classbuf); + return (ISC_FALSE); + } + } + + return (ISC_TRUE); +} + +static isc_boolean_t +is_answertarget_allowed(dns_view_t *view, dns_name_t *name, + dns_rdatatype_t type, dns_name_t *tname, + dns_name_t *domain) +{ + isc_result_t result; + dns_rbtnode_t *node = NULL; + char qnamebuf[DNS_NAME_FORMATSIZE]; + char tnamebuf[DNS_NAME_FORMATSIZE]; + char classbuf[64]; + char typebuf[64]; + + /* By default, we allow any target name. */ + if (view->denyanswernames == NULL) + return (ISC_TRUE); + + /* + * If the owner name matches one in the exclusion list, either exactly + * or partially, allow it. + */ + if (view->answernames_exclude != NULL) { + result = dns_rbt_findnode(view->answernames_exclude, name, NULL, + &node, NULL, 0, NULL, NULL); + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) + return (ISC_TRUE); + } + + /* + * If the target name is a subdomain of the search domain, allow it. + */ + if (dns_name_issubdomain(tname, domain)) + return (ISC_TRUE); + + /* + * Otherwise, apply filters. + */ + result = dns_rbt_findnode(view->denyanswernames, tname, NULL, &node, + NULL, 0, NULL, NULL); + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { + dns_name_format(name, qnamebuf, sizeof(qnamebuf)); + dns_name_format(tname, tnamebuf, sizeof(tnamebuf)); + dns_rdatatype_format(type, typebuf, sizeof(typebuf)); + dns_rdataclass_format(view->rdclass, classbuf, + sizeof(classbuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, + DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE, + "%s target %s denied for %s/%s", + typebuf, tnamebuf, qnamebuf, classbuf); + return (ISC_FALSE); + } + + return (ISC_TRUE); +} + /* * Handle a no-answer response (NXDOMAIN, NXRRSET, or referral). - * If bind8_ns_resp is ISC_TRUE, this is a suspected BIND 8 - * response to an NS query that should be treated as a referral - * even though the NS records occur in the answer section - * rather than the authority section. + * If look_in_options has LOOK_FOR_NS_IN_ANSWER then we look in the answer + * section for the NS RRset if the query type is NS; if it has + * LOOK_FOR_GLUE_IN_ANSWER we look for glue incorrectly returned in the answer + * section for A and AAAA queries. */ +#define LOOK_FOR_NS_IN_ANSWER 0x1 +#define LOOK_FOR_GLUE_IN_ANSWER 0x2 + static isc_result_t noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, - isc_boolean_t bind8_ns_resp) + unsigned int look_in_options) { isc_result_t result; dns_message_t *message; @@ -5120,11 +5265,16 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, dns_rdataset_t *rdataset, *ns_rdataset; isc_boolean_t aa, negative_response; dns_rdatatype_t type; - dns_section_t section = - bind8_ns_resp ? DNS_SECTION_ANSWER : DNS_SECTION_AUTHORITY; + dns_section_t section; FCTXTRACE("noanswer_response"); + if ((look_in_options & LOOK_FOR_NS_IN_ANSWER) != 0) { + INSIST(fctx->type == dns_rdatatype_ns); + section = DNS_SECTION_ANSWER; + } else + section = DNS_SECTION_AUTHORITY; + message = fctx->rmessage; /* @@ -5197,8 +5347,22 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, type = rdataset->covers; if (((type == dns_rdatatype_ns || type == dns_rdatatype_soa) && - !dns_name_issubdomain(qname, name))) + !dns_name_issubdomain(qname, name))) { + char qbuf[DNS_NAME_FORMATSIZE]; + char nbuf[DNS_NAME_FORMATSIZE]; + char tbuf[DNS_RDATATYPE_FORMATSIZE]; + dns_rdatatype_format(fctx->type, tbuf, + sizeof(tbuf)); + dns_name_format(name, nbuf, + sizeof(nbuf)); + dns_name_format(qname, qbuf, + sizeof(qbuf)); + log_formerr(fctx, + "unrelated %s %s in " + "%s authority section", + tbuf, qbuf, nbuf); return (DNS_R_FORMERR); + } if (type == dns_rdatatype_ns) { /* * NS or RRSIG NS. @@ -5208,8 +5372,14 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, if (rdataset->type == dns_rdatatype_ns) { if (ns_name != NULL && - name != ns_name) + name != ns_name) { + log_formerr(fctx, + "multiple NS " + "RRsets in " + "authority " + "section"); return (DNS_R_FORMERR); + } ns_name = name; ns_rdataset = rdataset; } @@ -5228,8 +5398,14 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, if (rdataset->type == dns_rdatatype_soa) { if (soa_name != NULL && - name != soa_name) + name != soa_name) { + log_formerr(fctx, + "multiple SOA " + "RRs in " + "authority " + "section"); return (DNS_R_FORMERR); + } soa_name = name; } name->attributes |= @@ -5305,15 +5481,25 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, * * These should only be here if * this is a referral, and there - * should only be one DS. + * should only be one DS RRset. */ - if (ns_name == NULL) + if (ns_name == NULL) { + log_formerr(fctx, + "DS with no " + "referral"); return (DNS_R_FORMERR); + } if (rdataset->type == dns_rdatatype_ds) { if (ds_name != NULL && - name != ds_name) + name != ds_name) { + log_formerr(fctx, + "DS doesn't " + "match " + "referral " + "(NS)"); return (DNS_R_FORMERR); + } ds_name = name; } name->attributes |= @@ -5363,6 +5549,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, /* * The responder is insane. */ + log_formerr(fctx, "invalid response"); return (DNS_R_FORMERR); } } @@ -5370,8 +5557,10 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, /* * If we found both NS and SOA, they should be the same name. */ - if (ns_name != NULL && soa_name != NULL && ns_name != soa_name) + if (ns_name != NULL && soa_name != NULL && ns_name != soa_name) { + log_formerr(fctx, "NS/SOA mismatch"); return (DNS_R_FORMERR); + } /* * Do we have a referral? (We only want to follow a referral if @@ -5384,14 +5573,18 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, * progress. We return DNS_R_FORMERR so that we'll keep * trying other servers. */ - if (dns_name_equal(ns_name, &fctx->domain)) + if (dns_name_equal(ns_name, &fctx->domain)) { + log_formerr(fctx, "non-improving referral"); return (DNS_R_FORMERR); + } /* * If the referral name is not a parent of the query * name, consider the responder insane. */ if (! dns_name_issubdomain(&fctx->name, ns_name)) { + /* Logged twice */ + log_formerr(fctx, "referral to non-parent"); FCTXTRACE("referral to non-parent"); return (DNS_R_FORMERR); } @@ -5405,6 +5598,20 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, fctx->attributes |= FCTX_ATTR_GLUING; (void)dns_rdataset_additionaldata(ns_rdataset, check_related, fctx); +#if CHECK_FOR_GLUE_IN_ANSWER + /* + * Look in the answer section for "glue" that is incorrectly + * returned as a answer. This is needed if the server also + * minimizes the response size by not adding records to the + * additional section that are in the answer section or if + * the record gets dropped due to message size constraints. + */ + if ((look_in_options & LOOK_FOR_GLUE_IN_ANSWER) != 0 && + (fctx->type == dns_rdatatype_aaaa || + fctx->type == dns_rdatatype_a)) + (void)dns_rdataset_additionaldata(ns_rdataset, + check_answer, fctx); +#endif fctx->attributes &= ~FCTX_ATTR_GLUING; /* * NS rdatasets with 0 TTL cause problems. @@ -5460,6 +5667,7 @@ answer_response(fetchctx_t *fctx) { unsigned int aflag; dns_rdatatype_t type; dns_fixedname_t dname, fqname; + dns_view_t *view; FCTXTRACE("answer_response"); @@ -5482,6 +5690,7 @@ answer_response(fetchctx_t *fctx) { aa = ISC_FALSE; qname = &fctx->name; type = fctx->type; + view = fctx->res->view; result = dns_message_firstname(message, DNS_SECTION_ANSWER); while (!done && result == ISC_R_SUCCESS) { name = NULL; @@ -5500,8 +5709,21 @@ answer_response(fetchctx_t *fctx) { * NSEC3 records are not allowed to * appear in the answer section. */ + log_formerr(fctx, "NSEC3 in answer"); return (DNS_R_FORMERR); } + + /* + * Apply filters, if given, on answers to reject + * a malicious attempt of rebinding. + */ + if ((rdataset->type == dns_rdatatype_a || + rdataset->type == dns_rdatatype_aaaa) && + !is_answeraddress_allowed(view, name, + rdataset)) { + return (DNS_R_SERVFAIL); + } + if (rdataset->type == type && !found_cname) { /* * We've found an ordinary answer. @@ -5540,8 +5762,16 @@ answer_response(fetchctx_t *fctx) { */ if (type == dns_rdatatype_rrsig || type == dns_rdatatype_dnskey || - type == dns_rdatatype_nsec) + type == dns_rdatatype_nsec || + type == dns_rdatatype_nsec3) { + char buf[DNS_RDATATYPE_FORMATSIZE]; + dns_rdatatype_format(fctx->type, + buf, sizeof(buf)); + log_formerr(fctx, + "CNAME response " + "for %s RR", buf); return (DNS_R_FORMERR); + } found = ISC_TRUE; found_cname = ISC_TRUE; want_chaining = ISC_TRUE; @@ -5550,6 +5780,14 @@ answer_response(fetchctx_t *fctx) { &tname); if (result != ISC_R_SUCCESS) return (result); + /* Apply filters on the target name. */ + if (!is_answertarget_allowed(view, + name, + rdataset->type, + &tname, + &fctx->domain)) { + return (DNS_R_SERVFAIL); + } } else if (rdataset->type == dns_rdatatype_rrsig && rdataset->covers == dns_rdatatype_cname @@ -5650,6 +5888,8 @@ answer_response(fetchctx_t *fctx) { rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { isc_boolean_t found_dname = ISC_FALSE; + dns_name_t *dname_name; + found = ISC_FALSE; aflag = 0; if (rdataset->type == dns_rdatatype_dname) { @@ -5660,12 +5900,15 @@ answer_response(fetchctx_t *fctx) { * If we're not chaining, then the * DNAME should not be external. */ - if (!chaining && external) + if (!chaining && external) { + log_formerr(fctx, + "external DNAME"); return (DNS_R_FORMERR); + } found = ISC_TRUE; want_chaining = ISC_TRUE; aflag = DNS_RDATASETATTR_ANSWER; - result = dname_target(rdataset, + result = dname_target(fctx, rdataset, qname, name, &dname); if (result == ISC_R_NOSPACE) { @@ -5679,6 +5922,15 @@ answer_response(fetchctx_t *fctx) { return (result); else found_dname = ISC_TRUE; + + dname_name = dns_fixedname_name(&dname); + if (!is_answertarget_allowed(view, + qname, + rdataset->type, + dname_name, + &fctx->domain)) { + return (DNS_R_SERVFAIL); + } } else if (rdataset->type == dns_rdatatype_rrsig && rdataset->covers == dns_rdatatype_dname) { @@ -5766,8 +6018,10 @@ answer_response(fetchctx_t *fctx) { /* * We should have found an answer. */ - if (!have_answer) + if (!have_answer) { + log_formerr(fctx, "reply has no answer"); return (DNS_R_FORMERR); + } /* * This response is now potentially cacheable. @@ -5784,15 +6038,18 @@ answer_response(fetchctx_t *fctx) { * If it isn't a noanswer response, no harm will be * done. */ - return (noanswer_response(fctx, qname, ISC_FALSE)); + return (noanswer_response(fctx, qname, 0)); } /* * We didn't end with an incomplete chain, so the rcode should be * "no error". */ - if (message->rcode != dns_rcode_noerror) + if (message->rcode != dns_rcode_noerror) { + log_formerr(fctx, "CNAME/DNAME chain complete, but RCODE " + "indicates error"); return (DNS_R_FORMERR); + } /* * Examine the authority section (if there is one). @@ -6129,6 +6386,39 @@ log_packet(dns_message_t *message, int level, isc_mem_t *mctx) { isc_mem_put(mctx, buf, len); } +static isc_boolean_t +iscname(fetchctx_t *fctx) { + isc_result_t result; + + result = dns_message_findname(fctx->rmessage, DNS_SECTION_ANSWER, + &fctx->name, dns_rdatatype_cname, 0, + NULL, NULL); + return (result == ISC_R_SUCCESS ? ISC_TRUE : ISC_FALSE); +} + +static isc_boolean_t +betterreferral(fetchctx_t *fctx) { + isc_result_t result; + dns_name_t *name; + dns_rdataset_t *rdataset; + dns_message_t *message = fctx->rmessage; + + for (result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); + result == ISC_R_SUCCESS; + result = dns_message_nextname(message, DNS_SECTION_AUTHORITY)) { + name = NULL; + dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); + if (!isstrictsubdomain(name, &fctx->domain)) + continue; + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + if (rdataset->type == dns_rdatatype_ns) + return (ISC_TRUE); + } + return (ISC_FALSE); +} + static void resquery_response(isc_task_t *task, isc_event_t *event) { isc_result_t result = ISC_R_SUCCESS; @@ -6180,6 +6470,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { fctx->timeouts = 0; fctx->timeout = ISC_FALSE; + fctx->addrinfo = query->addrinfo; /* * XXXRTH We should really get the current time just once. We @@ -6476,6 +6767,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * cannot make any more progress with this * fetch. */ + log_formerr(fctx, "server sent FORMERR"); result = DNS_R_FORMERR; } } else if (message->rcode == dns_rcode_yxdomain) { @@ -6590,27 +6882,62 @@ resquery_response(isc_task_t *task, isc_event_t *event) { (message->rcode == dns_rcode_noerror || message->rcode == dns_rcode_nxdomain)) { /* - * We've got answers. However, if we sent - * a BIND 8 server an NS query, it may have - * incorrectly responded with a non-authoritative - * answer instead of a referral. Since this - * answer lacks the SIGs necessary to do DNSSEC - * validation, we must invoke the following special - * kludge to treat it as a referral. + * [normal case] + * We've got answers. If it has an authoritative answer or an + * answer from a forwarder, we're done. */ - if (fctx->type == dns_rdatatype_ns && - (message->flags & DNS_MESSAGEFLAG_AA) == 0 && - !ISFORWARDER(query->addrinfo)) - { - result = noanswer_response(fctx, NULL, ISC_TRUE); + if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 || + ISFORWARDER(query->addrinfo)) + result = answer_response(fctx); + else if (iscname(fctx) && + fctx->type != dns_rdatatype_any && + fctx->type != dns_rdatatype_cname) { + /* + * A BIND8 server could return a non-authoritative + * answer when a CNAME is followed. We should treat + * it as a valid answer. + */ + result = answer_response(fctx); + } else if (fctx->type != dns_rdatatype_ns && + !betterreferral(fctx)) { + /* + * Lame response !!!. + */ + result = answer_response(fctx); + } else { + if (fctx->type == dns_rdatatype_ns) { + /* + * A BIND 8 server could incorrectly return a + * non-authoritative answer to an NS query + * instead of a referral. Since this answer + * lacks the SIGs necessary to do DNSSEC + * validation, we must invoke the following + * special kludge to treat it as a referral. + */ + result = noanswer_response(fctx, NULL, + LOOK_FOR_NS_IN_ANSWER); + } else { + /* + * Some other servers may still somehow include + * an answer when it should return a referral + * with an empty answer. Check to see if we can + * treat this as a referral by ignoring the + * answer. Further more, there may be an + * implementation that moves A/AAAA glue records + * to the answer section for that type of + * delegation when the query is for that glue + * record. LOOK_FOR_GLUE_IN_ANSWER will handle + * such a corner case. + */ + result = noanswer_response(fctx, NULL, + LOOK_FOR_GLUE_IN_ANSWER); + } if (result != DNS_R_DELEGATION) { /* - * The answer section must have contained - * something other than the NS records - * we asked for. Since AA is not set - * and the server is not a forwarder, - * it is technically lame and it's easier - * to treat it as such than to figure out + * At this point, AA is not set, the response + * is not a referral, and the server is not a + * forwarder. It is technically lame and it's + * easier to treat it as such than to figure out * some more elaborate course of action. */ broken_server = DNS_R_LAME; @@ -6619,7 +6946,6 @@ resquery_response(isc_task_t *task, isc_event_t *event) { } goto force_referral; } - result = answer_response(fctx); if (result != ISC_R_SUCCESS) { if (result == DNS_R_FORMERR) keep_trying = ISC_TRUE; @@ -6631,7 +6957,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { /* * NXDOMAIN, NXRDATASET, or referral. */ - result = noanswer_response(fctx, NULL, ISC_FALSE); + result = noanswer_response(fctx, NULL, 0); if (result == DNS_R_CHASEDSSERVERS) { } else if (result == DNS_R_DELEGATION) { force_referral: @@ -7043,6 +7369,7 @@ dns_resolver_create(dns_view_t *view, res->spillatmax = 100; res->spillattimer = NULL; res->zero_no_soa_ttl = ISC_FALSE; + res->query_timeout = DEFAULT_QUERY_TIMEOUT; res->ndisps = 0; res->nextdisp = 0; /* meaningless at this point, but init it */ res->nbuckets = ntasks; @@ -7194,6 +7521,7 @@ dns_resolver_create(dns_view_t *view, return (result); } +#ifdef BIND9 static void prime_done(isc_task_t *task, isc_event_t *event) { dns_resolver_t *res; @@ -7299,16 +7627,15 @@ dns_resolver_prime(dns_resolver_t *res) { } } } +#endif /* BIND9 */ void dns_resolver_freeze(dns_resolver_t *res) { - /* * Freeze resolver. */ REQUIRE(VALID_RESOLVER(res)); - REQUIRE(!res->frozen); res->frozen = ISC_TRUE; } @@ -8341,3 +8668,22 @@ dns_resolver_getoptions(dns_resolver_t *resolver) { return (resolver->options); } + +unsigned int +dns_resolver_gettimeout(dns_resolver_t *resolver) { + REQUIRE(VALID_RESOLVER(resolver)); + + return (resolver->query_timeout); +} + +void +dns_resolver_settimeout(dns_resolver_t *resolver, unsigned int seconds) { + REQUIRE(VALID_RESOLVER(resolver)); + + if (seconds == 0) + seconds = DEFAULT_QUERY_TIMEOUT; + if (seconds > MAXIMUM_QUERY_TIMEOUT) + seconds = MAXIMUM_QUERY_TIMEOUT; + + resolver->query_timeout = seconds; +} diff --git a/lib/dns/result.c b/lib/dns/result.c index 2b0457c..4cc194d 100644 --- a/lib/dns/result.c +++ b/lib/dns/result.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: result.c,v 1.125.48.2 2010-02-25 10:56:41 tbox Exp $ */ +/* $Id: result.c,v 1.132 2011-01-11 23:47:13 tbox Exp $ */ /*! \file */ @@ -105,7 +105,7 @@ static const char *text[DNS_R_NRESULTS] = { "no valid RRSIG", /*%< 59 DNS_R_NOVALIDSIG */ "no valid NSEC", /*%< 60 DNS_R_NOVALIDNSEC */ - "not insecure", /*%< 61 DNS_R_NOTINSECURE */ + "insecurity proof failed", /*%< 61 DNS_R_NOTINSECURE */ "unknown service", /*%< 62 DNS_R_UNKNOWNSERVICE */ "recoverable error occurred", /*%< 63 DNS_R_RECOVERABLE */ "unknown opt attribute record", /*%< 64 DNS_R_UNKNOWNOPT */ @@ -160,6 +160,7 @@ static const char *text[DNS_R_NRESULTS] = { "not master", /*%< 105 DNS_R_NOTMASTER */ "broken trust chain", /*%< 106 DNS_R_BROKENCHAIN */ + "expired", /*%< 106 DNS_R_EXPIRED */ }; static const char *rcode_text[DNS_R_NRCODERESULTS] = { diff --git a/lib/dns/rootns.c b/lib/dns/rootns.c index d51a0d6..40e2244 100644 --- a/lib/dns/rootns.c +++ b/lib/dns/rootns.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rootns.c,v 1.36.50.4 2010-06-18 05:37:50 marka Exp $ */ +/* $Id: rootns.c,v 1.40 2010-06-18 05:36:24 marka Exp $ */ /*! \file */ diff --git a/lib/dns/rpz.c b/lib/dns/rpz.c new file mode 100644 index 0000000..f809e7b --- /dev/null +++ b/lib/dns/rpz.c @@ -0,0 +1,1168 @@ +/* + * Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: rpz.c,v 1.7 2011-01-17 04:27:23 marka Exp $ */ + +/*! \file */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Parallel radix trees for databases of response policy IP addresses + * + * The radix or Patricia trees are somewhat specialized to handle response + * policy addresses by representing the two test of IP IP addresses and name + * server IP addresses in a single tree. + * + * Each leaf indicates that an IP address is listed in the IP address or the + * name server IP address policy sub-zone (or both) of the corresponding + * response response zone. The policy data such as a CNAME or an A record + * is kept in the policy zone. After an IP address has been found in a radix + * tree, the node in the policy zone's database is found by converting + * the IP address to a domain name in a canonical form. + * + * The response policy zone canonical form of IPv6 addresses is one of: + * prefix.W.W.W.W.W.W.W.W + * prefix.WORDS.zz + * prefix.WORDS.zz.WORDS + * prefix.zz.WORDS + * where + * prefix is the prefix length of the IPv6 address between 1 and 128 + * W is a number between 0 and 65535 + * WORDS is one or more numbers W separated with "." + * zz corresponds to :: in the standard IPv6 text representation + * + * The canonical form of IPv4 addresses is: + * prefix.B.B.B.B + * where + * prefix is the prefix length of the address between 1 and 32 + * B is a number between 0 and 255 + * + * IPv4 addresses are distinguished from IPv6 addresses by having + * 5 labels all of which are numbers, and a prefix between 1 and 32. + */ + + +/* + * Use a private definition of IPv6 addresses because s6_addr32 is not + * always defined and our IPv6 addresses are in non-standard byte order + */ +typedef isc_uint32_t dns_rpz_cidr_word_t; +#define DNS_RPZ_CIDR_WORD_BITS ((int)sizeof(dns_rpz_cidr_word_t)*8) +#define DNS_RPZ_CIDR_KEY_BITS ((int)sizeof(dns_rpz_cidr_key_t)*8) +#define DNS_RPZ_CIDR_WORDS (128/DNS_RPZ_CIDR_WORD_BITS) +typedef struct { + dns_rpz_cidr_word_t w[DNS_RPZ_CIDR_WORDS]; +} dns_rpz_cidr_key_t; + +#define ADDR_V4MAPPED 0xffff + +#define DNS_RPZ_WORD_MASK(b) \ + ((b) == 0 ? (dns_rpz_cidr_word_t)(-1) \ + : ((dns_rpz_cidr_word_t)(-1) \ + << (DNS_RPZ_CIDR_WORD_BITS - (b)))) + +#define DNS_RPZ_IP_BIT(ip, bitno) \ + (1 & ((ip)->w[(bitno)/DNS_RPZ_CIDR_WORD_BITS] >> \ + (DNS_RPZ_CIDR_WORD_BITS - 1 - ((bitno) % DNS_RPZ_CIDR_WORD_BITS)))) + +typedef struct dns_rpz_cidr_node dns_rpz_cidr_node_t; +typedef isc_uint8_t dns_rpz_cidr_flags_t; +struct dns_rpz_cidr_node { + dns_rpz_cidr_node_t *parent; + dns_rpz_cidr_node_t *child[2]; + dns_rpz_cidr_key_t ip; + dns_rpz_cidr_bits_t bits; + dns_rpz_cidr_flags_t flags; +#define DNS_RPZ_CIDR_FG_IP 0x01 /* has IP data or is parent of IP */ +#define DNS_RPZ_CIDR_FG_IP_DATA 0x02 /* has IP data */ +#define DNS_RPZ_CIDR_FG_NSIPv4 0x04 /* has or is parent of NSIPv4 data */ +#define DNS_RPZ_CIDR_FG_NSIPv6 0x08 /* has or is parent of NSIPv6 data */ +#define DNS_RPZ_CIDR_FG_NSIP_DATA 0x10 /* has NSIP data */ +}; + +struct dns_rpz_cidr { + isc_mem_t *mctx; + isc_boolean_t had_nsdname; + dns_rpz_cidr_node_t *root; + dns_name_t ip_name; /* RPZ_IP_ZONE.LOCALHOST. */ + dns_name_t nsip_name; /* RPZ_NSIP_ZONE.LOCALHOST. */ + dns_name_t nsdname_name; /* RPZ_NSDNAME_ZONE.LOCALHOST */ +}; + + +static isc_boolean_t have_rpz_zones = ISC_FALSE; + + +const char * +dns_rpz_type2str(dns_rpz_type_t type) +{ + switch (type) { + case DNS_RPZ_TYPE_QNAME: + return ("QNAME"); + case DNS_RPZ_TYPE_IP: + return ("IP"); + case DNS_RPZ_TYPE_NSIP: + return ("NSIP"); + case DNS_RPZ_TYPE_NSDNAME: + return ("NSDNAME"); + case DNS_RPZ_TYPE_BAD: + break; + } + FATAL_ERROR(__FILE__, __LINE__, + "impossible response policy zone type %d", type); + return ("impossible"); +} + + + +dns_rpz_policy_t +dns_rpz_str2policy(const char *str) +{ + if (str == NULL) + return (DNS_RPZ_POLICY_ERROR); + if (!strcasecmp(str, "given")) + return (DNS_RPZ_POLICY_GIVEN); + if (!strcasecmp(str, "no-op")) + return (DNS_RPZ_POLICY_NO_OP); + if (!strcasecmp(str, "nxdomain")) + return (DNS_RPZ_POLICY_NXDOMAIN); + if (!strcasecmp(str, "nodata")) + return (DNS_RPZ_POLICY_NODATA); + if (!strcasecmp(str, "cname")) + return (DNS_RPZ_POLICY_CNAME); + return (DNS_RPZ_POLICY_ERROR); +} + + + +/* + * Free the radix tree of a response policy database. + */ +void +dns_rpz_cidr_free(dns_rpz_cidr_t **cidrp) { + dns_rpz_cidr_node_t *cur, *child, *parent; + dns_rpz_cidr_t *cidr; + + REQUIRE(cidrp != NULL); + + cidr = *cidrp; + if (cidr == NULL) + return; + + cur = cidr->root; + while (cur != NULL) { + /* Depth first. */ + child = cur->child[0]; + if (child != NULL) { + cur = child; + continue; + } + child = cur->child[1]; + if (child != NULL) { + cur = child; + continue; + } + + /* Delete this leaf and go up. */ + parent = cur->parent; + if (parent == NULL) + cidr->root = NULL; + else + parent->child[parent->child[1] == cur] = NULL; + isc_mem_put(cidr->mctx, cur, sizeof(*cur)); + cur = parent; + } + + dns_name_free(&cidr->ip_name, cidr->mctx); + dns_name_free(&cidr->nsip_name, cidr->mctx); + dns_name_free(&cidr->nsdname_name, cidr->mctx); + isc_mem_put(cidr->mctx, cidr, sizeof(*cidr)); + *cidrp = NULL; +} + + + +/* + * Forget a view's list of policy zones. + */ +void +dns_rpz_view_destroy(dns_view_t *view) { + dns_rpz_zone_t *zone; + + REQUIRE(view != NULL); + + while (!ISC_LIST_EMPTY(view->rpz_zones)) { + zone = ISC_LIST_HEAD(view->rpz_zones); + ISC_LIST_UNLINK(view->rpz_zones, zone, link); + if (dns_name_dynamic(&zone->origin)) + dns_name_free(&zone->origin, view->mctx); + if (dns_name_dynamic(&zone->nsdname)) + dns_name_free(&zone->nsdname, view->mctx); + if (dns_name_dynamic(&zone->cname)) + dns_name_free(&zone->cname, view->mctx); + isc_mem_put(view->mctx, zone, sizeof(*zone)); + } +} + +/* + * Note that we have at least one response policy zone. + * It would be better for something to tell the rbtdb code that the + * zone is in at least one view's list of policy zones. + */ +void +dns_rpz_set_need(isc_boolean_t need) +{ + have_rpz_zones = need; +} + + +isc_boolean_t +dns_rpz_needed(void) +{ + return (have_rpz_zones); +} + + + +/* + * Start a new radix tree for a response policy zone. + */ +isc_result_t +dns_rpz_new_cidr(isc_mem_t *mctx, dns_name_t *origin, + dns_rpz_cidr_t **rbtdb_cidr) +{ + isc_result_t result; + dns_rpz_cidr_t *cidr; + + REQUIRE(rbtdb_cidr != NULL && *rbtdb_cidr == NULL); + + /* + * Only if there is at least one response policy zone. + */ + if (!have_rpz_zones) + return (ISC_R_SUCCESS); + + cidr = isc_mem_get(mctx, sizeof(*cidr)); + if (cidr == NULL) + return (ISC_R_NOMEMORY); + memset(cidr, 0, sizeof(*cidr)); + cidr->mctx = mctx; + + dns_name_init(&cidr->ip_name, NULL); + result = dns_name_fromstring2(&cidr->ip_name, DNS_RPZ_IP_ZONE, origin, + DNS_NAME_DOWNCASE, mctx); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, cidr, sizeof(*cidr)); + return (result); + } + + dns_name_init(&cidr->nsip_name, NULL); + result = dns_name_fromstring2(&cidr->nsip_name, DNS_RPZ_NSIP_ZONE, + origin, DNS_NAME_DOWNCASE, mctx); + if (result != ISC_R_SUCCESS) { + dns_name_free(&cidr->ip_name, mctx); + isc_mem_put(mctx, cidr, sizeof(*cidr)); + return (result); + } + + dns_name_init(&cidr->nsdname_name, NULL); + result = dns_name_fromstring2(&cidr->nsdname_name, DNS_RPZ_NSDNAME_ZONE, + origin, DNS_NAME_DOWNCASE, mctx); + if (result != ISC_R_SUCCESS) { + dns_name_free(&cidr->nsip_name, mctx); + dns_name_free(&cidr->ip_name, mctx); + isc_mem_put(mctx, cidr, sizeof(*cidr)); + return (result); + } + + *rbtdb_cidr = cidr; + return (ISC_R_SUCCESS); +} + + +/* + * See if a policy zone has IP, NSIP, or NSDNAME rules or records. + */ +void +dns_rpz_enabled(dns_rpz_cidr_t *cidr, dns_rpz_st_t *st) { + if (cidr->root != NULL && + (cidr->root->flags & DNS_RPZ_CIDR_FG_IP) != 0) + st->state |= DNS_RPZ_HAVE_IP; + if (cidr->root != NULL && + (cidr->root->flags & DNS_RPZ_CIDR_FG_NSIPv4) != 0) + st->state |= DNS_RPZ_HAVE_NSIPv4; + if (cidr->root != NULL && + (cidr->root->flags & DNS_RPZ_CIDR_FG_NSIPv6) != 0) + st->state |= DNS_RPZ_HAVE_NSIPv6; + if (cidr->had_nsdname) + st->state |= DNS_RPZ_HAD_NSDNAME; +} + +static inline dns_rpz_cidr_flags_t +get_flags(const dns_rpz_cidr_key_t *ip, dns_rpz_cidr_bits_t prefix, + dns_rpz_type_t rpz_type) +{ + if (rpz_type == DNS_RPZ_TYPE_NSIP) { + if (prefix >= 96 && + ip->w[0] == 0 && ip->w[1] == 0 && + ip->w[2] == ADDR_V4MAPPED) + return (DNS_RPZ_CIDR_FG_NSIP_DATA | + DNS_RPZ_CIDR_FG_NSIPv4); + else + return (DNS_RPZ_CIDR_FG_NSIP_DATA | + DNS_RPZ_CIDR_FG_NSIPv6); + } else { + return (DNS_RPZ_CIDR_FG_IP | DNS_RPZ_CIDR_FG_IP_DATA); + } +} + + + +/* + * Mark a node as having IP or NSIP data and all of its parents + * as members of the IP or NSIP tree. + */ +static void +set_node_flags(dns_rpz_cidr_node_t *node, dns_rpz_type_t rpz_type) { + dns_rpz_cidr_flags_t flags; + + flags = get_flags(&node->ip, node->bits, rpz_type); + node->flags |= flags; + flags &= ~(DNS_RPZ_CIDR_FG_NSIP_DATA | DNS_RPZ_CIDR_FG_IP_DATA); + for (;;) { + node = node->parent; + if (node == NULL) + return; + node->flags |= flags; + } +} + + + +/* + * Make a radix tree node. + */ +static dns_rpz_cidr_node_t * +new_node(dns_rpz_cidr_t *cidr, const dns_rpz_cidr_key_t *ip, + dns_rpz_cidr_bits_t bits, dns_rpz_cidr_flags_t flags) +{ + dns_rpz_cidr_node_t *node; + int i, words, wlen; + + node = isc_mem_get(cidr->mctx, sizeof(*node)); + if (node == NULL) + return (NULL); + memset(node, 0, sizeof(*node)); + + node->flags = flags & ~(DNS_RPZ_CIDR_FG_IP_DATA | + DNS_RPZ_CIDR_FG_NSIP_DATA); + + node->bits = bits; + words = bits / DNS_RPZ_CIDR_WORD_BITS; + wlen = bits % DNS_RPZ_CIDR_WORD_BITS; + i = 0; + while (i < words) { + node->ip.w[i] = ip->w[i]; + ++i; + } + if (wlen != 0) { + node->ip.w[i] = ip->w[i] & DNS_RPZ_WORD_MASK(wlen); + ++i; + } + while (i < DNS_RPZ_CIDR_WORDS) + node->ip.w[i++] = 0; + + return (node); +} + + + +static void +badname(int level, dns_name_t *name, const char *comment) +{ + char printname[DNS_NAME_FORMATSIZE]; + + if (isc_log_wouldlog(dns_lctx, level)) { + dns_name_format(name, printname, sizeof(printname)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_RBTDB, level, + "invalid response policy name \"%s\"%s", + printname, comment); + } +} + + + +/* + * Convert an IP address from radix tree binary (host byte order) to + * to its canonical response policy domain name and its name in the + * policy zone. + */ +static isc_result_t +ip2name(dns_rpz_cidr_t *cidr, const dns_rpz_cidr_key_t *tgt_ip, + dns_rpz_cidr_bits_t tgt_prefix, dns_rpz_type_t type, + dns_name_t *canon_name, dns_name_t *search_name) +{ +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 46 +#endif + int w[DNS_RPZ_CIDR_WORDS*2]; + char str[1+8+1+INET6_ADDRSTRLEN+1]; + isc_buffer_t buffer; + dns_name_t *name; + isc_result_t result; + isc_boolean_t zeros; + int i, n, len; + + if (tgt_prefix > 96 && + tgt_ip->w[0] == 0 && + tgt_ip->w[1] == 0 && + tgt_ip->w[2] == ADDR_V4MAPPED) { + len = snprintf(str, sizeof(str), "%d.%d.%d.%d.%d", + tgt_prefix - 96, + tgt_ip->w[3] & 0xff, + (tgt_ip->w[3]>>8) & 0xff, + (tgt_ip->w[3]>>16) & 0xff, + (tgt_ip->w[3]>>24) & 0xff); + if (len == -1 || len > (int)sizeof(str)) + return (ISC_R_FAILURE); + } else { + for (i = 0; i < DNS_RPZ_CIDR_WORDS; i++) { + w[i*2+1] = ((tgt_ip->w[DNS_RPZ_CIDR_WORDS-1-i] >> 16) + & 0xffff); + w[i*2] = tgt_ip->w[DNS_RPZ_CIDR_WORDS-1-i] & 0xffff; + } + zeros = ISC_FALSE; + len = snprintf(str, sizeof(str), "%d", tgt_prefix); + if (len == -1) + return (ISC_R_FAILURE); + i = 0; + while (i < DNS_RPZ_CIDR_WORDS * 2) { + if (w[i] != 0 || zeros + || i >= DNS_RPZ_CIDR_WORDS * 2 - 1 + || w[i+1] != 0) { + INSIST((size_t)len <= sizeof(str)); + n = snprintf(&str[len], sizeof(str) - len, + ".%x", w[i++]); + if (n < 0) + return (ISC_R_FAILURE); + len += n; + } else { + zeros = ISC_TRUE; + INSIST((size_t)len <= sizeof(str)); + n = snprintf(&str[len], sizeof(str) - len, + ".zz"); + if (n < 0) + return (ISC_R_FAILURE); + len += n; + i += 2; + while (i < DNS_RPZ_CIDR_WORDS * 2 && w[i] == 0) + ++i; + } + if (len > (int)sizeof(str)) + return (ISC_R_FAILURE); + } + } + + if (canon_name != NULL) { + isc__buffer_init(&buffer, str, sizeof(str)); + isc__buffer_add(&buffer, len); + result = dns_name_fromtext(canon_name, &buffer, + dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) + return (result); + } + if (search_name != NULL) { + isc__buffer_init(&buffer, str, sizeof(str)); + isc__buffer_add(&buffer, len); + if (type == DNS_RPZ_TYPE_NSIP) + name = &cidr->nsip_name; + else + name = &cidr->ip_name; + result = dns_name_fromtext(search_name, &buffer, name, 0, NULL); + if (result != ISC_R_SUCCESS) + return (result); + } + return (ISC_R_SUCCESS); +} + + + +/* + * Decide which kind of IP address response policy zone a name is in. + */ +static dns_rpz_type_t +set_type(dns_rpz_cidr_t *cidr, dns_name_t *name) { + + if (dns_name_issubdomain(name, &cidr->ip_name)) + return (DNS_RPZ_TYPE_IP); + + /* + * Require `./configure --enable-rpz-nsip` and nsdname + * until consistency problems are resolved. + */ +#ifdef ENABLE_RPZ_NSIP + if (dns_name_issubdomain(name, &cidr->nsip_name)) + return (DNS_RPZ_TYPE_NSIP); +#endif + +#ifdef ENABLE_RPZ_NSDNAME + if (dns_name_issubdomain(name, &cidr->nsdname_name)) + return (DNS_RPZ_TYPE_NSDNAME); +#endif + + return (DNS_RPZ_TYPE_QNAME); +} + + + +/* + * Convert an IP address from canonical response policy domain name form + * to radix tree binary (host byte order). + */ +static isc_result_t +name2ipkey(dns_rpz_cidr_t *cidr, int level, dns_name_t *src_name, + dns_rpz_type_t type, dns_rpz_cidr_key_t *tgt_ip, + dns_rpz_cidr_bits_t *tgt_prefix) +{ + isc_buffer_t buffer; + unsigned char data[DNS_NAME_MAXWIRE+1]; + dns_fixedname_t fname; + dns_name_t *name; + const char *cp, *end; + char *cp2; + int ip_labels; + dns_rpz_cidr_bits_t bits; + unsigned long prefix, l; + int i; + + /* + * Need at least enough labels for the shortest name, + * :: or 128.*.RPZ_x_ZONE.rpz.LOCALHOST. + */ + ip_labels = dns_name_countlabels(src_name); + ip_labels -= dns_name_countlabels(&cidr->ip_name); + ip_labels--; + if (ip_labels < 1) { + badname(level, src_name, ", too short"); + return (ISC_R_FAILURE); + } + + /* + * Get text for the IP address without RPZ_x_ZONE.rpz.LOCALHOST. + */ + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + dns_name_split(src_name, dns_name_countlabels(&cidr->ip_name), + name, NULL); + isc_buffer_init(&buffer, data, sizeof(data)); + dns_name_totext(name, ISC_TRUE, &buffer); + isc_buffer_putuint8(&buffer, '\0'); + cp = isc_buffer_base(&buffer); + + prefix = strtoul(cp, &cp2, 10); + if (prefix < 1U || prefix > 128U || *cp2 != '.') { + badname(level, src_name, ", bad prefix length"); + return (ISC_R_FAILURE); + } + cp = cp2+1; + + end = isc_buffer_used(&buffer); + if (ip_labels == 4 && !strchr(cp, 'z')) { + /* + * Convert an IPv4 address + * from the form "prefix.w.z.y.x" + */ + if (prefix > 32U) { + badname(level, src_name, "; bad IPv4 prefix length"); + return (ISC_R_FAILURE); + } + prefix += 96; + *tgt_prefix = (dns_rpz_cidr_bits_t)prefix; + tgt_ip->w[0] = 0; + tgt_ip->w[1] = 0; + tgt_ip->w[2] = ADDR_V4MAPPED; + tgt_ip->w[3] = 0; + for (i = 0; i < 32; i += 8) { + l = strtoul(cp, &cp2, 10); + if (l > 255U || (*cp2 != '.' && *cp2 != '\0')) { + badname(level, src_name, "; bad IPv4 address"); + return (ISC_R_FAILURE); + } + tgt_ip->w[3] |= l << i; + cp = cp2 + 1; + } + } else { + /* + * Convert a text IPv6 address. + */ + *tgt_prefix = (dns_rpz_cidr_bits_t)prefix; + for (i = 0; + ip_labels > 0 && i < DNS_RPZ_CIDR_WORDS * 2; + ip_labels--) { + if (cp[0] == 'z' && cp[1] == 'z' && + (cp[2] == '.' || cp[2] == '\0') && + i <= 6) { + do { + if ((i & 1) == 0) + tgt_ip->w[3-i/2] = 0; + ++i; + } while (ip_labels + i <= 8); + cp += 3; + } else { + l = strtoul(cp, &cp2, 16); + if (l > 0xffffu || + (*cp2 != '.' && *cp2 != '\0')) { + badname(level, src_name, ""); + return (ISC_R_FAILURE); + } + if ((i & 1) == 0) + tgt_ip->w[3-i/2] = l; + else + tgt_ip->w[3-i/2] |= l << 16; + i++; + cp = cp2 + 1; + } + } + } + if (cp != end) { + badname(level, src_name, ""); + return (ISC_R_FAILURE); + } + + /* + * Check for 1s after the prefix length. + */ + bits = (dns_rpz_cidr_bits_t)prefix; + while (bits < DNS_RPZ_CIDR_KEY_BITS) { + dns_rpz_cidr_word_t aword; + + i = bits % DNS_RPZ_CIDR_WORD_BITS; + aword = tgt_ip->w[bits / DNS_RPZ_CIDR_WORD_BITS]; + if ((aword & ~DNS_RPZ_WORD_MASK(i)) != 0) { + badname(level, src_name, "; wrong prefix length"); + return (ISC_R_FAILURE); + } + bits -= i; + bits += DNS_RPZ_CIDR_WORD_BITS; + } + + /* + * Convert the IPv6 address back to a canonical policy domain name + * to ensure that it is in canonical form. + */ + if (ISC_R_SUCCESS != ip2name(cidr, tgt_ip, (dns_rpz_cidr_bits_t)prefix, + type, NULL, name) || + !dns_name_equal(src_name, name)) { + badname(level, src_name, "; not canonical"); + return (ISC_R_FAILURE); + } + + return (ISC_R_SUCCESS); +} + + + +/* + * find first differing bit + */ +static int +ffbit(dns_rpz_cidr_word_t w) { + int bit; + + if (w == 0) + return (DNS_RPZ_CIDR_WORD_BITS); + for (bit = 0; (w & (1U << (DNS_RPZ_CIDR_WORD_BITS-1))) == 0; bit++) + w <<= 1; + return (bit); +} + + + +/* + * find the first differing bit in two keys + */ +static int +diff_keys(const dns_rpz_cidr_key_t *key1, dns_rpz_cidr_bits_t bits1, + const dns_rpz_cidr_key_t *key2, dns_rpz_cidr_bits_t bits2) +{ + dns_rpz_cidr_word_t delta; + dns_rpz_cidr_bits_t maxbit, bit; + int i; + + maxbit = ISC_MIN(bits1, bits2); + + /* + * find the first differing words + */ + for (i = 0, bit = 0; + bit <= maxbit; + i++, bit += DNS_RPZ_CIDR_WORD_BITS) { + delta = key1->w[i] ^ key2->w[i]; + if (delta != 0) { + bit += ffbit(delta); + break; + } + } + return (ISC_MIN(bit, maxbit)); +} + + + +/* + * Search a radix tree for an IP address for ordinary lookup + * or for a CIDR block adding or deleting an entry + * The tree read (for simple search) or write lock must be held by the caller. + * + * return ISC_R_SUCCESS, ISC_R_NOTFOUND, DNS_R_PARTIALMATCH, ISC_R_EXISTS, + * ISC_R_NOMEMORY + */ +static isc_result_t +search(dns_rpz_cidr_t *cidr, const dns_rpz_cidr_key_t *tgt_ip, + dns_rpz_cidr_bits_t tgt_prefix, dns_rpz_type_t type, + isc_boolean_t create, + dns_rpz_cidr_node_t **found) /* NULL or longest match node */ +{ + dns_rpz_cidr_node_t *cur, *parent, *child, *new_parent, *sibling; + int cur_num, child_num; + dns_rpz_cidr_bits_t dbit; + dns_rpz_cidr_flags_t flags, data_flag; + isc_result_t find_result; + + flags = get_flags(tgt_ip, tgt_prefix, type); + data_flag = flags & (DNS_RPZ_CIDR_FG_IP_DATA | + DNS_RPZ_CIDR_FG_NSIP_DATA); + + find_result = ISC_R_NOTFOUND; + if (found != NULL) + *found = NULL; + cur = cidr->root; + parent = NULL; + cur_num = 0; + for (;;) { + if (cur == NULL) { + /* + * No child so we cannot go down. Fail or + * add the target as a child of the current parent. + */ + if (!create) + return (find_result); + child = new_node(cidr, tgt_ip, tgt_prefix, 0); + if (child == NULL) + return (ISC_R_NOMEMORY); + if (parent == NULL) + cidr->root = child; + else + parent->child[cur_num] = child; + child->parent = parent; + set_node_flags(child, type); + if (found != NULL) + *found = cur; + return (ISC_R_SUCCESS); + } + + /* + * Pretend a node not in the correct tree does not exist + * if we are not adding to the tree, + * If we are adding, then continue down to eventually + * add a node and mark/put this node in the correct tree. + */ + if ((cur->flags & flags) == 0 && !create) + return (find_result); + + dbit = diff_keys(tgt_ip, tgt_prefix, &cur->ip, cur->bits); + /* + * dbit <= tgt_prefix and dbit <= cur->bits always. + * We are finished searching if we matched all of the target. + */ + if (dbit == tgt_prefix) { + if (tgt_prefix == cur->bits) { + /* + * The current node matches the target exactly. + * It is the answer if it has data. + */ + if ((cur->flags & data_flag) != 0) { + if (create) + return (ISC_R_EXISTS); + if (found != NULL) + *found = cur; + return (ISC_R_SUCCESS); + } else if (create) { + /* + * The node had no data but does now. + */ + set_node_flags(cur, type); + if (found != NULL) + *found = cur; + return (ISC_R_SUCCESS); + } + return (find_result); + } + + /* + * We know tgt_prefix < cur_bits which means that + * the target is shorter than the current node. + * Add the target as the current node's parent. + */ + if (!create) + return (find_result); + + new_parent = new_node(cidr, tgt_ip, tgt_prefix, + cur->flags); + if (new_parent == NULL) + return (ISC_R_NOMEMORY); + new_parent->parent = parent; + if (parent == NULL) + cidr->root = new_parent; + else + parent->child[cur_num] = new_parent; + child_num = DNS_RPZ_IP_BIT(&cur->ip, tgt_prefix+1); + new_parent->child[child_num] = cur; + cur->parent = new_parent; + set_node_flags(new_parent, type); + if (found != NULL) + *found = new_parent; + return (ISC_R_SUCCESS); + } + + if (dbit == cur->bits) { + /* + * We have a partial match by matching of all of the + * current node but only part of the target. + * Try to go down. + */ + if ((cur->flags & data_flag) != 0) { + find_result = DNS_R_PARTIALMATCH; + if (found != NULL) + *found = cur; + } + + parent = cur; + cur_num = DNS_RPZ_IP_BIT(tgt_ip, dbit); + cur = cur->child[cur_num]; + continue; + } + + + /* + * dbit < tgt_prefix and dbit < cur->bits, + * so we failed to match both the target and the current node. + * Insert a fork of a parent above the current node and + * add the target as a sibling of the current node + */ + if (!create) + return (find_result); + + sibling = new_node(cidr, tgt_ip, tgt_prefix, 0); + if (sibling == NULL) + return (ISC_R_NOMEMORY); + new_parent = new_node(cidr, tgt_ip, dbit, cur->flags); + if (new_parent == NULL) { + isc_mem_put(cidr->mctx, sibling, sizeof(*sibling)); + return (ISC_R_NOMEMORY); + } + new_parent->parent = parent; + if (parent == NULL) + cidr->root = new_parent; + else + parent->child[cur_num] = new_parent; + child_num = DNS_RPZ_IP_BIT(tgt_ip, dbit); + new_parent->child[child_num] = sibling; + new_parent->child[1-child_num] = cur; + cur->parent = new_parent; + sibling->parent = new_parent; + set_node_flags(sibling, type); + if (found != NULL) + *found = sibling; + return (ISC_R_SUCCESS); + } +} + + + +/* + * Add an IP address to the radix tree of a response policy database. + * The tree write lock must be held by the caller. + */ +void +dns_rpz_cidr_addip(dns_rpz_cidr_t *cidr, dns_name_t *name) +{ + dns_rpz_cidr_key_t tgt_ip; + dns_rpz_cidr_bits_t tgt_prefix; + dns_rpz_type_t type; + + if (cidr == NULL) + return; + + /* + * no worries if the new name is not an IP address + */ + type = set_type(cidr, name); + switch (type) { + case DNS_RPZ_TYPE_IP: + case DNS_RPZ_TYPE_NSIP: + break; + case DNS_RPZ_TYPE_NSDNAME: + cidr->had_nsdname = ISC_TRUE; + return; + case DNS_RPZ_TYPE_QNAME: + case DNS_RPZ_TYPE_BAD: + return; + } + if (ISC_R_SUCCESS != name2ipkey(cidr, DNS_RPZ_ERROR_LEVEL, name, + type, &tgt_ip, &tgt_prefix)) + return; + + if (ISC_R_EXISTS == search(cidr, &tgt_ip, tgt_prefix, type, + ISC_TRUE, NULL) && + isc_log_wouldlog(dns_lctx, DNS_RPZ_ERROR_LEVEL)) { + char printname[DNS_NAME_FORMATSIZE]; + + dns_name_format(name, printname, sizeof(printname)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL, + "duplicate response policy name \"%s\"", + printname); + } +} + + + +/* + * Delete an IP address from the radix tree of a response policy database. + * The tree write lock must be held by the caller. + */ +void +dns_rpz_cidr_deleteip(dns_rpz_cidr_t *cidr, dns_name_t *name) { + dns_rpz_cidr_key_t tgt_ip; + dns_rpz_cidr_bits_t tgt_prefix; + dns_rpz_type_t type; + dns_rpz_cidr_node_t *tgt = NULL, *parent, *child; + dns_rpz_cidr_flags_t flags, data_flag; + + if (cidr == NULL) + return; + + /* + * Decide which kind of policy zone IP address it is, if either + * and then find its node. + */ + type = set_type(cidr, name); + switch (type) { + case DNS_RPZ_TYPE_IP: + case DNS_RPZ_TYPE_NSIP: + break; + case DNS_RPZ_TYPE_NSDNAME: + /* + * We cannot easily count nsdnames because + * internal rbt nodes get deleted. + */ + return; + case DNS_RPZ_TYPE_QNAME: + case DNS_RPZ_TYPE_BAD: + return; + } + + /* + * Do not get excited about the deletion of interior rbt nodes. + */ + if (ISC_R_SUCCESS != name2ipkey(cidr, DNS_RPZ_DEBUG_LEVEL2, name, + type, &tgt_ip, &tgt_prefix)) + return; + if (ISC_R_SUCCESS != search(cidr, &tgt_ip, tgt_prefix, type, + ISC_FALSE, &tgt)) { + if (isc_log_wouldlog(dns_lctx, DNS_RPZ_ERROR_LEVEL)) { + char printname[DNS_NAME_FORMATSIZE]; + + dns_name_format(name, printname, sizeof(printname)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL, + "missing response policy node \"%s\"", + printname); + } + return; + } + + /* + * Mark the node and its parents to reflect the deleted IP address. + */ + flags = get_flags(&tgt_ip, tgt_prefix, type); + data_flag = flags & (DNS_RPZ_CIDR_FG_IP_DATA | + DNS_RPZ_CIDR_FG_NSIP_DATA); + tgt->flags &= ~data_flag; + for (parent = tgt; parent != NULL; parent = parent->parent) { + if ((parent->flags & data_flag) != 0 || + (parent->child[0] != NULL && + (parent->child[0]->flags & flags) != 0) || + (parent->child[1] != NULL && + (parent->child[1]->flags & flags) != 0)) + break; + parent->flags &= ~flags; + } + + /* + * We might need to delete 2 nodes. + */ + do { + /* + * The node is now useless if it has no data of its own + * and 0 or 1 children. We are finished if it is not useless. + */ + if ((child = tgt->child[0]) != NULL) { + if (tgt->child[1] != NULL) + return; + } else { + child = tgt->child[1]; + } + if ((tgt->flags & (DNS_RPZ_CIDR_FG_IP_DATA | + DNS_RPZ_CIDR_FG_NSIP_DATA)) != 0) + return; + + /* + * Replace the pointer to this node in the parent with + * the remaining child or NULL. + */ + parent = tgt->parent; + if (parent == NULL) { + cidr->root = child; + } else { + parent->child[parent->child[1] == tgt] = child; + } + /* + * If the child exists fix up its parent pointer. + */ + if (child != NULL) + child->parent = parent; + isc_mem_put(cidr->mctx, tgt, sizeof(*tgt)); + + tgt = parent; + } while (tgt != NULL); +} + + + +/* + * Caller must hold tree lock. + * Return ISC_R_NOTFOUND + * or ISC_R_SUCCESS and the found entry's canonical and search names + * and its prefix length + */ +isc_result_t +dns_rpz_cidr_find(dns_rpz_cidr_t *cidr, const isc_netaddr_t *netaddr, + dns_rpz_type_t type, dns_name_t *canon_name, + dns_name_t *search_name, dns_rpz_cidr_bits_t *prefix) +{ + dns_rpz_cidr_key_t tgt_ip; + isc_result_t result; + dns_rpz_cidr_node_t *found; + int i; + + /* + * Convert IP address to CIDR tree key. + */ + if (netaddr->family == AF_INET) { + tgt_ip.w[0] = 0; + tgt_ip.w[1] = 0; + tgt_ip.w[2] = ADDR_V4MAPPED; + tgt_ip.w[3] = ntohl(netaddr->type.in.s_addr); + } else if (netaddr->family == AF_INET6) { + dns_rpz_cidr_key_t src_ip6; + + /* + * Given the int aligned struct in_addr member of netaddr->type + * one could cast netaddr->type.in6 to dns_rpz_cidr_key_t *, + * but there are objections. + */ + memcpy(src_ip6.w, &netaddr->type.in6, sizeof(src_ip6.w)); + for (i = 0; i < 4; i++) { + tgt_ip.w[i] = ntohl(src_ip6.w[i]); + } + } else { + return (ISC_R_NOTFOUND); + } + + result = search(cidr, &tgt_ip, 128, type, ISC_FALSE, &found); + if (result != ISC_R_SUCCESS && result != DNS_R_PARTIALMATCH) + return (result); + + *prefix = found->bits; + return (ip2name(cidr, &found->ip, found->bits, type, + canon_name, search_name)); +} + + + +/* + * Translate CNAME rdata to a QNAME response policy action. + */ +dns_rpz_policy_t +dns_rpz_decode_cname(dns_rdataset_t *rdataset, dns_name_t *selfname) { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_cname_t cname; + isc_result_t result; + + result = dns_rdataset_first(rdataset); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &cname, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_rdata_reset(&rdata); + + /* + * CNAME . means NXDOMAIN + */ + if (dns_name_equal(&cname.cname, dns_rootname)) + return (DNS_RPZ_POLICY_NXDOMAIN); + + /* + * CNAME *. means NODATA + */ + if (dns_name_countlabels(&cname.cname) == 2 + && dns_name_iswildcard(&cname.cname)) + return (DNS_RPZ_POLICY_NODATA); + + /* + * 128.1.0.127.rpz-ip CNAME 128.1.0.0.127. means "do not rewrite" + */ + if (selfname != NULL && dns_name_equal(&cname.cname, selfname)) + return (DNS_RPZ_POLICY_NO_OP); + + /* + * evil.com CNAME garden.net rewrites www.evil.com to www.garden.net. + */ + return (DNS_RPZ_POLICY_RECORD); +} diff --git a/lib/dns/rriterator.c b/lib/dns/rriterator.c new file mode 100644 index 0000000..31d67af --- /dev/null +++ b/lib/dns/rriterator.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: rriterator.c,v 1.2 2009-06-30 02:52:32 each Exp $ */ + +/*! \file */ + +/*** + *** Imports + ***/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/*** + *** RRiterator methods + ***/ + +isc_result_t +dns_rriterator_init(dns_rriterator_t *it, dns_db_t *db, dns_dbversion_t *ver, + isc_stdtime_t now) +{ + isc_result_t result; + it->magic = RRITERATOR_MAGIC; + it->db = db; + it->dbit = NULL; + it->ver = ver; + it->now = now; + it->node = NULL; + result = dns_db_createiterator(it->db, 0, &it->dbit); + if (result != ISC_R_SUCCESS) + return (result); + it->rdatasetit = NULL; + dns_rdata_init(&it->rdata); + dns_rdataset_init(&it->rdataset); + dns_fixedname_init(&it->fixedname); + INSIST(! dns_rdataset_isassociated(&it->rdataset)); + it->result = ISC_R_SUCCESS; + return (it->result); +} + +isc_result_t +dns_rriterator_first(dns_rriterator_t *it) { + REQUIRE(VALID_RRITERATOR(it)); + /* Reset state */ + if (dns_rdataset_isassociated(&it->rdataset)) + dns_rdataset_disassociate(&it->rdataset); + if (it->rdatasetit != NULL) + dns_rdatasetiter_destroy(&it->rdatasetit); + if (it->node != NULL) + dns_db_detachnode(it->db, &it->node); + it->result = dns_dbiterator_first(it->dbit); + + /* + * The top node may be empty when out of zone glue exists. + * Walk the tree to find the first node with data. + */ + while (it->result == ISC_R_SUCCESS) { + it->result = dns_dbiterator_current(it->dbit, &it->node, + dns_fixedname_name(&it->fixedname)); + if (it->result != ISC_R_SUCCESS) + return (it->result); + + it->result = dns_db_allrdatasets(it->db, it->node, it->ver, + it->now, &it->rdatasetit); + if (it->result != ISC_R_SUCCESS) + return (it->result); + + it->result = dns_rdatasetiter_first(it->rdatasetit); + if (it->result != ISC_R_SUCCESS) { + /* + * This node is empty. Try next node. + */ + dns_rdatasetiter_destroy(&it->rdatasetit); + dns_db_detachnode(it->db, &it->node); + it->result = dns_dbiterator_next(it->dbit); + continue; + } + dns_rdatasetiter_current(it->rdatasetit, &it->rdataset); + it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER; + it->result = dns_rdataset_first(&it->rdataset); + return (it->result); + } + return (it->result); +} + +isc_result_t +dns_rriterator_nextrrset(dns_rriterator_t *it) { + REQUIRE(VALID_RRITERATOR(it)); + if (dns_rdataset_isassociated(&it->rdataset)) + dns_rdataset_disassociate(&it->rdataset); + it->result = dns_rdatasetiter_next(it->rdatasetit); + /* + * The while loop body is executed more than once + * only when an empty dbnode needs to be skipped. + */ + while (it->result == ISC_R_NOMORE) { + dns_rdatasetiter_destroy(&it->rdatasetit); + dns_db_detachnode(it->db, &it->node); + it->result = dns_dbiterator_next(it->dbit); + if (it->result == ISC_R_NOMORE) { + /* We are at the end of the entire database. */ + return (it->result); + } + if (it->result != ISC_R_SUCCESS) + return (it->result); + it->result = dns_dbiterator_current(it->dbit, &it->node, + dns_fixedname_name(&it->fixedname)); + if (it->result != ISC_R_SUCCESS) + return (it->result); + it->result = dns_db_allrdatasets(it->db, it->node, it->ver, + it->now, &it->rdatasetit); + if (it->result != ISC_R_SUCCESS) + return (it->result); + it->result = dns_rdatasetiter_first(it->rdatasetit); + } + if (it->result != ISC_R_SUCCESS) + return (it->result); + dns_rdatasetiter_current(it->rdatasetit, &it->rdataset); + it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER; + it->result = dns_rdataset_first(&it->rdataset); + return (it->result); +} + +isc_result_t +dns_rriterator_next(dns_rriterator_t *it) { + REQUIRE(VALID_RRITERATOR(it)); + if (it->result != ISC_R_SUCCESS) + return (it->result); + + INSIST(it->dbit != NULL); + INSIST(it->node != NULL); + INSIST(it->rdatasetit != NULL); + + it->result = dns_rdataset_next(&it->rdataset); + if (it->result == ISC_R_NOMORE) + return (dns_rriterator_nextrrset(it)); + return (it->result); +} + +void +dns_rriterator_pause(dns_rriterator_t *it) { + REQUIRE(VALID_RRITERATOR(it)); + RUNTIME_CHECK(dns_dbiterator_pause(it->dbit) == ISC_R_SUCCESS); +} + +void +dns_rriterator_destroy(dns_rriterator_t *it) { + REQUIRE(VALID_RRITERATOR(it)); + if (dns_rdataset_isassociated(&it->rdataset)) + dns_rdataset_disassociate(&it->rdataset); + if (it->rdatasetit != NULL) + dns_rdatasetiter_destroy(&it->rdatasetit); + if (it->node != NULL) + dns_db_detachnode(it->db, &it->node); + dns_dbiterator_destroy(&it->dbit); +} + +void +dns_rriterator_current(dns_rriterator_t *it, dns_name_t **name, + isc_uint32_t *ttl, dns_rdataset_t **rdataset, + dns_rdata_t **rdata) +{ + REQUIRE(name != NULL && *name == NULL); + REQUIRE(VALID_RRITERATOR(it)); + REQUIRE(it->result == ISC_R_SUCCESS); + + *name = dns_fixedname_name(&it->fixedname); + *ttl = it->rdataset.ttl; + + dns_rdata_reset(&it->rdata); + dns_rdataset_current(&it->rdataset, &it->rdata); + + if (rdataset) + *rdataset = &it->rdataset; + + if (rdata) + *rdata = &it->rdata; +} diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c index 49c6430..d27007d 100644 --- a/lib/dns/sdb.c +++ b/lib/dns/sdb.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sdb.c,v 1.66.48.6 2010-08-16 05:21:42 marka Exp $ */ +/* $Id: sdb.c,v 1.76 2011-01-13 04:59:25 tbox Exp $ */ /*! \file */ @@ -450,7 +450,7 @@ getnode(dns_sdballnodes_t *allnodes, const char *name, dns_sdbnode_t **nodep) { isc_buffer_init(&b, name, strlen(name)); isc_buffer_add(&b, strlen(name)); - result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL); + result = dns_name_fromtext(newname, &b, origin, 0, NULL); if (result != ISC_R_SUCCESS) return (result); @@ -1253,6 +1253,8 @@ static dns_dbmethods_t sdb_methods = { NULL, NULL, NULL, + NULL, + NULL, NULL }; diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c index 6be315a..e684e1d 100644 --- a/lib/dns/sdlz.c +++ b/lib/dns/sdlz.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2005-2010 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2005-2011 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -50,7 +50,7 @@ * USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sdlz.c,v 1.18.50.6 2010-08-16 05:21:42 marka Exp $ */ +/* $Id: sdlz.c,v 1.31 2011-01-13 06:29:16 marka Exp $ */ /*! \file */ @@ -108,6 +108,8 @@ struct dns_sdlz_db { isc_mutex_t refcnt_lock; /* Locked */ unsigned int references; + dns_dbversion_t *future_version; + int dummy_version; }; struct dns_sdlzlookup { @@ -164,8 +166,6 @@ typedef struct sdlz_rdatasetiter { /* This is a reasonable value */ #define SDLZ_DEFAULT_TTL (60 * 60 * 24) -static int dummy; - #ifdef __COVERITY__ #define MAYBE_LOCK(imp) LOCK(&imp->driverlock) #define MAYBE_UNLOCK(imp) UNLOCK(&imp->driverlock) @@ -225,11 +225,22 @@ static dns_dbiteratormethods_t dbiterator_methods = { * Utility functions */ -/*% Converts the input string to lowercase, in place. */ +/* + * Log a message at the given level + */ +static void +sdlz_log(int level, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(level), + fmt, ap); + va_end(ap); +} +/*% Converts the input string to lowercase, in place. */ static void dns_sdlz_tolower(char *str) { - unsigned int len = strlen(str); unsigned int i; @@ -237,7 +248,6 @@ dns_sdlz_tolower(char *str) { if (str[i] >= 'A' && str[i] <= 'Z') str[i] += 32; } - } static inline unsigned int @@ -381,43 +391,79 @@ dump(dns_db_t *db, dns_dbversion_t *version, const char *filename, static void currentversion(dns_db_t *db, dns_dbversion_t **versionp) { + dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db; + REQUIRE(VALID_SDLZDB(sdlz)); REQUIRE(versionp != NULL && *versionp == NULL); - UNUSED(db); - - *versionp = (void *) &dummy; + *versionp = (void *) &sdlz->dummy_version; return; } static isc_result_t newversion(dns_db_t *db, dns_dbversion_t **versionp) { - UNUSED(db); - UNUSED(versionp); + dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db; + char origin[DNS_NAME_MAXTEXT + 1]; + isc_result_t result; - return (ISC_R_NOTIMPLEMENTED); + REQUIRE(VALID_SDLZDB(sdlz)); + + if (sdlz->dlzimp->methods->newversion == NULL) + return (ISC_R_NOTIMPLEMENTED); + + dns_name_format(&sdlz->common.origin, origin, sizeof(origin)); + + result = sdlz->dlzimp->methods->newversion(origin, + sdlz->dlzimp->driverarg, + sdlz->dbdata, versionp); + if (result != ISC_R_SUCCESS) { + sdlz_log(ISC_LOG_ERROR, + "sdlz newversion on origin %s failed : %s", + origin, isc_result_totext(result)); + return (result); + } + + sdlz->future_version = *versionp; + return (ISC_R_SUCCESS); } static void attachversion(dns_db_t *db, dns_dbversion_t *source, dns_dbversion_t **targetp) { - REQUIRE(source != NULL && source == (void *) &dummy); + dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db; + + REQUIRE(VALID_SDLZDB(sdlz)); + REQUIRE(source != NULL && source == (void *)&sdlz->dummy_version); - UNUSED(db); - UNUSED(source); - UNUSED(targetp); *targetp = source; } static void closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) { - REQUIRE(versionp != NULL && *versionp == (void *) &dummy); - REQUIRE(commit == ISC_FALSE); + dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db; + char origin[DNS_NAME_MAXTEXT + 1]; - UNUSED(db); - UNUSED(commit); + REQUIRE(VALID_SDLZDB(sdlz)); + REQUIRE(versionp != NULL); + + if (*versionp == (void *)&sdlz->dummy_version) { + *versionp = NULL; + return; + } + + REQUIRE(*versionp == sdlz->future_version); + REQUIRE(sdlz->dlzimp->methods->closeversion != NULL); + + dns_name_format(&sdlz->common.origin, origin, sizeof(origin)); - *versionp = NULL; + sdlz->dlzimp->methods->closeversion(origin, commit, + sdlz->dlzimp->driverarg, + sdlz->dbdata, versionp); + if (*versionp != NULL) + sdlz_log(ISC_LOG_ERROR, + "sdlz closeversion on origin %s failed", origin); + + sdlz->future_version = NULL; } static isc_result_t @@ -506,11 +552,11 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, dns_sdlzauthorityfunc_t authority; REQUIRE(VALID_SDLZDB(sdlz)); - REQUIRE(create == ISC_FALSE); REQUIRE(nodep != NULL && *nodep == NULL); - UNUSED(name); - UNUSED(create); + if (sdlz->dlzimp->methods->newversion == NULL) { + REQUIRE(create == ISC_FALSE); + } isc_buffer_init(&b, namestr, sizeof(namestr)); if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVEOWNER) != 0) { @@ -558,7 +604,7 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, * if the host (namestr) was not found, try to lookup a * "wildcard" host. */ - if (result != ISC_R_SUCCESS) { + if (result != ISC_R_SUCCESS && !create) { result = sdlz->dlzimp->methods->lookup(zonestr, "*", sdlz->dlzimp->driverarg, sdlz->dbdata, node); @@ -566,7 +612,7 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, MAYBE_UNLOCK(sdlz->dlzimp); - if (result != ISC_R_SUCCESS && !isorigin) { + if (result != ISC_R_SUCCESS && !isorigin && !create) { destroynode(node); return (result); } @@ -584,6 +630,23 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, } } + if (node->name == NULL) { + node->name = isc_mem_get(sdlz->common.mctx, + sizeof(dns_name_t)); + if (node->name == NULL) { + destroynode(node); + return (ISC_R_NOMEMORY); + } + dns_name_init(node->name, NULL); + result = dns_name_dup(name, sdlz->common.mctx, node->name); + if (result != ISC_R_SUCCESS) { + isc_mem_put(sdlz->common.mctx, node->name, + sizeof(dns_name_t)); + destroynode(node); + return (result); + } + } + *nodep = node; return (ISC_R_SUCCESS); } @@ -778,7 +841,7 @@ find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, REQUIRE(VALID_SDLZDB(sdlz)); REQUIRE(nodep == NULL || *nodep == NULL); - REQUIRE(version == NULL || version == (void *) &dummy); + REQUIRE(version == NULL || version == (void*)&sdlz->dummy_version); UNUSED(options); UNUSED(sdlz); @@ -920,9 +983,14 @@ static isc_result_t allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_stdtime_t now, dns_rdatasetiter_t **iteratorp) { + dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *) db; sdlz_rdatasetiter_t *iterator; - REQUIRE(version == NULL || version == &dummy); + REQUIRE(VALID_SDLZDB(sdlz)); + + REQUIRE(version == NULL || + version == (void*)&sdlz->dummy_version || + version == sdlz->future_version); UNUSED(version); UNUSED(now); @@ -945,47 +1013,139 @@ allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, } static isc_result_t +modrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + dns_rdataset_t *rdataset, unsigned int options, + dns_sdlzmodrdataset_t mod_function) +{ + dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db; + dns_master_style_t *style = NULL; + isc_result_t result; + isc_buffer_t *buffer = NULL; + isc_mem_t *mctx; + dns_sdlznode_t *sdlznode; + char *rdatastr = NULL; + char name[DNS_NAME_MAXTEXT + 1]; + + REQUIRE(VALID_SDLZDB(sdlz)); + + if (mod_function == NULL) + return (ISC_R_NOTIMPLEMENTED); + + sdlznode = (dns_sdlznode_t *)node; + + UNUSED(options); + + dns_name_format(sdlznode->name, name, sizeof(name)); + + mctx = sdlz->common.mctx; + + result = isc_buffer_allocate(mctx, &buffer, 1024); + if (result != ISC_R_SUCCESS) + return (result); + + result = dns_master_stylecreate(&style, 0, 0, 0, 0, 0, 0, 1, mctx); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dns_master_rdatasettotext(sdlznode->name, rdataset, + style, buffer); + if (result != ISC_R_SUCCESS) + goto cleanup; + + if (isc_buffer_usedlength(buffer) < 1) { + result = ISC_R_BADADDRESSFORM; + goto cleanup; + } + + rdatastr = isc_buffer_base(buffer); + if (rdatastr == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + rdatastr[isc_buffer_usedlength(buffer) - 1] = 0; + + MAYBE_LOCK(sdlz->dlzimp); + result = mod_function(name, rdatastr, sdlz->dlzimp->driverarg, + sdlz->dbdata, version); + MAYBE_UNLOCK(sdlz->dlzimp); + +cleanup: + isc_buffer_free(&buffer); + if (style != NULL) + dns_master_styledestroy(&style, mctx); + + return (result); +} + +static isc_result_t addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options, dns_rdataset_t *addedrdataset) { - UNUSED(db); - UNUSED(node); - UNUSED(version); + dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db; + isc_result_t result; + UNUSED(now); - UNUSED(rdataset); - UNUSED(options); UNUSED(addedrdataset); + REQUIRE(VALID_SDLZDB(sdlz)); - return (ISC_R_NOTIMPLEMENTED); + if (sdlz->dlzimp->methods->addrdataset == NULL) + return (ISC_R_NOTIMPLEMENTED); + + result = modrdataset(db, node, version, rdataset, options, + sdlz->dlzimp->methods->addrdataset); + return (result); } + static isc_result_t subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_rdataset_t *rdataset, unsigned int options, dns_rdataset_t *newrdataset) { - UNUSED(db); - UNUSED(node); - UNUSED(version); - UNUSED(rdataset); - UNUSED(options); + dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db; + isc_result_t result; + UNUSED(newrdataset); + REQUIRE(VALID_SDLZDB(sdlz)); - return (ISC_R_NOTIMPLEMENTED); + if (sdlz->dlzimp->methods->subtractrdataset == NULL) { + return (ISC_R_NOTIMPLEMENTED); + } + + result = modrdataset(db, node, version, rdataset, options, + sdlz->dlzimp->methods->subtractrdataset); + return (result); } static isc_result_t deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_rdatatype_t type, dns_rdatatype_t covers) { - UNUSED(db); - UNUSED(node); - UNUSED(version); - UNUSED(type); + dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db; + char name[DNS_NAME_MAXTEXT + 1]; + char b_type[DNS_RDATATYPE_FORMATSIZE]; + dns_sdlznode_t *sdlznode; + isc_result_t result; + UNUSED(covers); - return (ISC_R_NOTIMPLEMENTED); + REQUIRE(VALID_SDLZDB(sdlz)); + + if (sdlz->dlzimp->methods->delrdataset == NULL) + return (ISC_R_NOTIMPLEMENTED); + + sdlznode = (dns_sdlznode_t *)node; + dns_name_format(sdlznode->name, name, sizeof(name)); + dns_rdatatype_format(type, b_type, sizeof(b_type)); + + MAYBE_LOCK(sdlz->dlzimp); + result = sdlz->dlzimp->methods->delrdataset(name, b_type, + sdlz->dlzimp->driverarg, + sdlz->dbdata, version); + MAYBE_UNLOCK(sdlz->dlzimp); + + return (result); } static isc_boolean_t @@ -1021,6 +1181,26 @@ settask(dns_db_t *db, isc_task_t *task) { } +/* + * getoriginnode() is used by the update code to find the + * dns_rdatatype_dnskey record for a zone + */ +static isc_result_t +getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) { + dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db; + isc_result_t result; + + REQUIRE(VALID_SDLZDB(sdlz)); + if (sdlz->dlzimp->methods->newversion == NULL) + return (ISC_R_NOTIMPLEMENTED); + + result = findnode(db, &sdlz->common.origin, ISC_FALSE, nodep); + if (result != ISC_R_SUCCESS) + sdlz_log(ISC_LOG_ERROR, "sdlz getoriginnode failed : %s", + isc_result_totext(result)); + return (result); +} + static dns_dbmethods_t sdlzdb_methods = { attach, detach, @@ -1049,6 +1229,8 @@ static dns_dbmethods_t sdlzdb_methods = { ispersistent, overmem, settask, + getoriginnode, + NULL, NULL, NULL, NULL, @@ -1371,9 +1553,7 @@ dns_sdlzcreate(isc_mem_t *mctx, const char *dlzname, unsigned int argc, isc_result_t result = ISC_R_NOTFOUND; /* Write debugging message to log */ - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), - "Loading SDLZ driver."); + sdlz_log(ISC_LOG_DEBUG(2), "Loading SDLZ driver."); /* * Performs checks to make sure data is as we expect it to be. @@ -1395,13 +1575,9 @@ dns_sdlzcreate(isc_mem_t *mctx, const char *dlzname, unsigned int argc, /* Write debugging message to log */ if (result == ISC_R_SUCCESS) { - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), - "SDLZ driver loaded successfully."); + sdlz_log(ISC_LOG_DEBUG(2), "SDLZ driver loaded successfully."); } else { - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, - "SDLZ driver failed to load."); + sdlz_log(ISC_LOG_ERROR, "SDLZ driver failed to load."); } return (result); @@ -1414,9 +1590,7 @@ dns_sdlzdestroy(void *driverdata, void **dbdata) dns_sdlzimplementation_t *imp; /* Write debugging message to log */ - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), - "Unloading SDLZ driver."); + sdlz_log(ISC_LOG_DEBUG(2), "Unloading SDLZ driver."); imp = driverdata; @@ -1472,11 +1646,97 @@ dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx, return (result); } + +static isc_result_t +dns_sdlzconfigure(void *driverarg, void *dbdata, dns_view_t *view) +{ + isc_result_t result; + dns_sdlzimplementation_t *imp; + + REQUIRE(driverarg != NULL); + + imp = (dns_sdlzimplementation_t *) driverarg; + + /* Call SDLZ driver's configure method */ + if (imp->methods->configure != NULL) { + MAYBE_LOCK(imp); + result = imp->methods->configure(view, imp->driverarg, dbdata); + MAYBE_UNLOCK(imp); + } else { + result = ISC_R_SUCCESS; + } + + return (result); +} + +static isc_boolean_t +dns_sdlzssumatch(dns_name_t *signer, dns_name_t *name, isc_netaddr_t *tcpaddr, + dns_rdatatype_t type, const dst_key_t *key, void *driverarg, + void *dbdata) +{ + dns_sdlzimplementation_t *imp; + char b_signer[DNS_NAME_FORMATSIZE]; + char b_name[DNS_NAME_FORMATSIZE]; + char b_addr[ISC_NETADDR_FORMATSIZE]; + char b_type[DNS_RDATATYPE_FORMATSIZE]; + char b_key[DST_KEY_FORMATSIZE]; + isc_buffer_t *tkey_token; + isc_region_t token_region; + isc_uint32_t token_len = 0; + isc_boolean_t ret; + + REQUIRE(driverarg != NULL); + + imp = (dns_sdlzimplementation_t *) driverarg; + if (imp->methods->ssumatch == NULL) + return (ISC_FALSE); + + /* + * Format the request elements. sdlz operates on strings, not + * structures + */ + if (signer) + dns_name_format(signer, b_signer, sizeof(b_signer)); + else + b_signer[0] = 0; + + dns_name_format(name, b_name, sizeof(b_name)); + + if (tcpaddr) + isc_netaddr_format(tcpaddr, b_addr, sizeof(b_addr)); + else + b_addr[0] = 0; + + dns_rdatatype_format(type, b_type, sizeof(b_type)); + + if (key) + dst_key_format(key, b_key, sizeof(b_key)); + else + b_key[0] = 0; + + tkey_token = dst_key_tkeytoken(key); + + if (tkey_token) { + isc_buffer_region(tkey_token, &token_region); + token_len = token_region.length; + } + + MAYBE_LOCK(imp); + ret = imp->methods->ssumatch(b_signer, b_name, b_addr, b_type, b_key, + token_len, + token_len ? token_region.base : NULL, + imp->driverarg, dbdata); + MAYBE_UNLOCK(imp); + return (ret); +} + static dns_dlzmethods_t sdlzmethods = { dns_sdlzcreate, dns_sdlzdestroy, dns_sdlzfindzone, - dns_sdlzallowzonexfr + dns_sdlzallowzonexfr, + dns_sdlzconfigure, + dns_sdlzssumatch }; /* @@ -1530,8 +1790,16 @@ dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl, ISC_LINK_INIT(rdatalist, link); ISC_LIST_APPEND(lookup->lists, rdatalist, link); } else - if (rdatalist->ttl != ttl) - return (DNS_R_BADTTL); + if (rdatalist->ttl > ttl) { + /* + * BIND9 doesn't enforce all RRs in an RRset + * having the same TTL, as per RFC 2136, + * section 7.12. If a DLZ backend has + * different TTLs, then the best + * we can do is return the lowest. + */ + rdatalist->ttl = ttl; + } rdata = isc_mem_get(mctx, sizeof(dns_rdata_t)); if (rdata == NULL) @@ -1615,7 +1883,7 @@ dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name, isc_buffer_init(&b, name, strlen(name)); isc_buffer_add(&b, strlen(name)); - result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL); + result = dns_name_fromtext(newname, &b, origin, 0, NULL); if (result != ISC_R_SUCCESS) return (result); @@ -1694,9 +1962,7 @@ dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods, DNS_SDLZFLAG_THREADSAFE)) == 0); /* Write debugging message to log */ - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), - "Registering SDLZ driver '%s'", drivername); + sdlz_log(ISC_LOG_DEBUG(2), "Registering SDLZ driver '%s'", drivername); /* * Allocate memory for a sdlz_implementation object. Error if @@ -1769,9 +2035,7 @@ dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp) { isc_mem_t *mctx; /* Write debugging message to log */ - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), - "Unregistering SDLZ driver."); + sdlz_log(ISC_LOG_DEBUG(2), "Unregistering SDLZ driver."); /* * Performs checks to make sure data is as we expect it to be. @@ -1797,3 +2061,16 @@ dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp) { *sdlzimp = NULL; } + + +isc_result_t +dns_sdlz_setdb(dns_dlzdb_t *dlzdatabase, dns_rdataclass_t rdclass, + dns_name_t *name, dns_db_t **dbp) +{ + isc_result_t result; + + result = dns_sdlzcreateDBP(dlzdatabase->mctx, + dlzdatabase->implementation->driverarg, + dlzdatabase->dbdata, name, rdclass, dbp); + return (result); +} diff --git a/lib/dns/soa.c b/lib/dns/soa.c index f338586..bd0d185 100644 --- a/lib/dns/soa.c +++ b/lib/dns/soa.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,15 +15,18 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: soa.c,v 1.8 2007-06-19 23:47:16 tbox Exp $ */ +/* $Id: soa.c,v 1.12 2009-09-10 02:18:40 each Exp $ */ /*! \file */ #include +#include +#include #include #include +#include #include static inline isc_uint32_t @@ -60,6 +63,39 @@ soa_get(dns_rdata_t *rdata, int offset) { return (decode_uint32(rdata->data + rdata->length - 20 + offset)); } +isc_result_t +dns_soa_buildrdata(dns_name_t *origin, dns_name_t *contact, + dns_rdataclass_t rdclass, + isc_uint32_t serial, isc_uint32_t refresh, + isc_uint32_t retry, isc_uint32_t expire, + isc_uint32_t minimum, unsigned char *buffer, + dns_rdata_t *rdata) { + dns_rdata_soa_t soa; + isc_buffer_t rdatabuf; + + REQUIRE(origin != NULL); + REQUIRE(contact != NULL); + + memset(buffer, 0, DNS_SOA_BUFFERSIZE); + isc_buffer_init(&rdatabuf, buffer, DNS_SOA_BUFFERSIZE); + + soa.common.rdtype = dns_rdatatype_soa; + soa.common.rdclass = rdclass; + soa.mctx = NULL; + soa.serial = serial; + soa.refresh = refresh; + soa.retry = retry; + soa.expire = expire; + soa.minimum = minimum; + dns_name_init(&soa.origin, NULL); + dns_name_clone(origin, &soa.origin); + dns_name_init(&soa.contact, NULL); + dns_name_clone(contact, &soa.contact); + + return (dns_rdata_fromstruct(rdata, rdclass, dns_rdatatype_soa, + &soa, &rdatabuf)); +} + isc_uint32_t dns_soa_getserial(dns_rdata_t *rdata) { return soa_get(rdata, 0); diff --git a/lib/dns/spnego.c b/lib/dns/spnego.c index ad15331..5ad492c 100644 --- a/lib/dns/spnego.c +++ b/lib/dns/spnego.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2006-2011 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: spnego.c,v 1.8.118.4 2009-07-21 07:27:13 marka Exp $ */ +/* $Id: spnego.c,v 1.16 2011-01-11 23:47:13 tbox Exp $ */ /*! \file * \brief @@ -172,6 +172,8 @@ /* asn1_err.h */ /* Generated from ../../../lib/asn1/asn1_err.et */ +#ifndef ERROR_TABLE_BASE_asn1 +/* these may be brought in already via gssapi_krb5.h */ typedef enum asn1_error_number { ASN1_BAD_TIMEFORMAT = 1859794432, ASN1_MISSING_FIELD = 1859794433, @@ -186,6 +188,7 @@ typedef enum asn1_error_number { } asn1_error_number; #define ERROR_TABLE_BASE_asn1 1859794432 +#endif #define __asn1_common_definitions__ @@ -409,7 +412,7 @@ code_NegTokenArg(OM_uint32 * minor_status, { OM_uint32 ret; u_char *buf; - size_t buf_size, buf_len; + size_t buf_size, buf_len = 0; buf_size = 1024; buf = malloc(buf_size); diff --git a/lib/dns/ssu.c b/lib/dns/ssu.c index 128071c..eb13551 100644 --- a/lib/dns/ssu.c +++ b/lib/dns/ssu.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008, 2010, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -17,7 +17,7 @@ /*! \file */ /* - * $Id: ssu.c,v 1.34 2008-01-18 23:46:58 tbox Exp $ + * $Id: ssu.c,v 1.38 2011-01-06 23:47:00 tbox Exp $ * Principal Author: Brian Wellington */ @@ -30,11 +30,13 @@ #include #include +#include #include #include #include #include +#include #define SSUTABLEMAGIC ISC_MAGIC('S', 'S', 'U', 'T') #define VALID_SSUTABLE(table) ISC_MAGIC_VALID(table, SSUTABLEMAGIC) @@ -59,6 +61,7 @@ struct dns_ssutable { isc_mem_t *mctx; unsigned int references; isc_mutex_t lock; + dns_dlzdb_t *dlzdatabase; ISC_LIST(dns_ssurule_t) rules; }; @@ -345,7 +348,8 @@ stf_from_address(dns_name_t *stfself, isc_netaddr_t *tcpaddr) { isc_boolean_t dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer, dns_name_t *name, isc_netaddr_t *tcpaddr, - dns_rdatatype_t type) + dns_rdatatype_t type, + const dst_key_t *key) { dns_ssurule_t *rule; unsigned int i; @@ -483,10 +487,27 @@ dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer, if (!dns_name_equal(stfself, name)) continue; break; + case DNS_SSUMATCHTYPE_EXTERNAL: + if (!dns_ssu_external_match(rule->identity, signer, + name, tcpaddr, type, key, + table->mctx)) + continue; + break; + case DNS_SSUMATCHTYPE_DLZ: + if (!dns_dlz_ssumatch(table->dlzdatabase, signer, + name, tcpaddr, type, key)) + continue; + break; } if (rule->ntypes == 0) { - if (!isusertype(type)) + /* + * If this is a DLZ rule, then the DLZ ssu + * checks will have already checked + * the type. + */ + if (rule->matchtype != DNS_SSUMATCHTYPE_DLZ && + !isusertype(type)) continue; } else { for (i = 0; i < rule->ntypes; i++) { @@ -550,3 +571,42 @@ dns_ssutable_nextrule(dns_ssurule_t *rule, dns_ssurule_t **nextrule) { *nextrule = ISC_LIST_NEXT(rule, link); return (*nextrule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE); } + +/* + * Create a specialised SSU table that points at an external DLZ database + */ +isc_result_t +dns_ssutable_createdlz(isc_mem_t *mctx, dns_ssutable_t **tablep, + dns_dlzdb_t *dlzdatabase) +{ + isc_result_t result; + dns_ssurule_t *rule; + dns_ssutable_t *table = NULL; + + REQUIRE(tablep != NULL && *tablep == NULL); + + result = dns_ssutable_create(mctx, &table); + if (result != ISC_R_SUCCESS) + return (result); + + table->dlzdatabase = dlzdatabase; + + rule = isc_mem_get(table->mctx, sizeof(dns_ssurule_t)); + if (rule == NULL) { + dns_ssutable_detach(&table); + return (ISC_R_NOMEMORY); + } + + rule->identity = NULL; + rule->name = NULL; + rule->types = NULL; + rule->grant = ISC_TRUE; + rule->matchtype = DNS_SSUMATCHTYPE_DLZ; + rule->ntypes = 0; + rule->types = NULL; + rule->magic = SSURULEMAGIC; + + ISC_LIST_INITANDAPPEND(table->rules, rule, link); + *tablep = table; + return (ISC_R_SUCCESS); +} diff --git a/lib/dns/ssu_external.c b/lib/dns/ssu_external.c new file mode 100644 index 0000000..ac72a1f --- /dev/null +++ b/lib/dns/ssu_external.c @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: ssu_external.c,v 1.7 2011-01-13 07:05:57 marka Exp $ */ + +/* + * This implements external update-policy rules. This allows permission + * to update a zone to be checked by consulting an external daemon (e.g., + * kerberos). + */ + +#include +#include +#include + +#ifdef ISC_PLATFORM_HAVESYSUNH +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + +static void +ssu_e_log(int level, const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_SECURITY, + DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(level), fmt, ap); + va_end(ap); +} + + +/* + * Connect to a UNIX domain socket. + */ +static int +ux_socket_connect(const char *path) { + int fd = -1; +#ifdef ISC_PLATFORM_HAVESYSUNH + struct sockaddr_un addr; + + REQUIRE(path != NULL); + + if (strlen(path) > sizeof(addr.sun_path)) { + ssu_e_log(3, "ssu_external: socket path '%s' " + "longer than system maximum %u", + path, sizeof(addr.sun_path)); + return (-1); + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path, sizeof(addr.sun_path)); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(errno, strbuf, sizeof(strbuf)); + ssu_e_log(3, "ssu_external: unable to create socket - %s", + strbuf); + return (-1); + } + + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(errno, strbuf, sizeof(strbuf)); + ssu_e_log(3, "ssu_external: unable to connect to " + "socket '%s' - %s", + path, strbuf); + close(fd); + return (-1); + } +#endif + return (fd); +} + +/* Change this version if you update the format of the request */ +#define SSU_EXTERNAL_VERSION 1 + +/* + * Perform an update-policy rule check against an external application + * over a socket. + * + * This currently only supports local: for unix domain datagram sockets. + * + * Note that by using a datagram socket and creating a new socket each + * time we avoid the need for locking and allow for parallel access to + * the authorization server. + */ +isc_boolean_t +dns_ssu_external_match(dns_name_t *identity, + dns_name_t *signer, dns_name_t *name, + isc_netaddr_t *tcpaddr, dns_rdatatype_t type, + const dst_key_t *key, isc_mem_t *mctx) +{ + char b_identity[DNS_NAME_FORMATSIZE]; + char b_signer[DNS_NAME_FORMATSIZE]; + char b_name[DNS_NAME_FORMATSIZE]; + char b_addr[ISC_NETADDR_FORMATSIZE]; + char b_type[DNS_RDATATYPE_FORMATSIZE]; + char b_key[DST_KEY_FORMATSIZE]; + isc_buffer_t *tkey_token; + int fd; + const char *sock_path; + size_t req_len; + isc_region_t token_region; + unsigned char *data; + isc_buffer_t buf; + isc_uint32_t token_len = 0; + isc_uint32_t reply; + ssize_t ret; + + /* The identity contains local:/path/to/socket */ + dns_name_format(identity, b_identity, sizeof(b_identity)); + + /* For now only local: is supported */ + if (strncmp(b_identity, "local:", 6) != 0) { + ssu_e_log(3, "ssu_external: invalid socket path '%s'", + b_identity); + return (ISC_FALSE); + } + sock_path = &b_identity[6]; + + fd = ux_socket_connect(sock_path); + if (fd == -1) + return (ISC_FALSE); + + tkey_token = dst_key_tkeytoken(key); + + /* Format the request elements */ + if (signer) + dns_name_format(signer, b_signer, sizeof(b_signer)); + else + b_signer[0] = 0; + + dns_name_format(name, b_name, sizeof(b_name)); + + if (tcpaddr) + isc_netaddr_format(tcpaddr, b_addr, sizeof(b_addr)); + else + b_addr[0] = 0; + + dns_rdatatype_format(type, b_type, sizeof(b_type)); + + if (key) + dst_key_format(key, b_key, sizeof(b_key)); + else + b_key[0] = 0; + + if (tkey_token) { + isc_buffer_region(tkey_token, &token_region); + token_len = token_region.length; + } + + /* Work out how big the request will be */ + req_len = sizeof(isc_uint32_t) + /* Format version */ + sizeof(isc_uint32_t) + /* Length */ + strlen(b_signer) + 1 + /* Signer */ + strlen(b_name) + 1 + /* Name */ + strlen(b_addr) + 1 + /* Address */ + strlen(b_type) + 1 + /* Type */ + strlen(b_key) + 1 + /* Key */ + sizeof(isc_uint32_t) + /* tkey_token length */ + token_len; /* tkey_token */ + + + /* format the buffer */ + data = isc_mem_allocate(mctx, req_len); + if (data == NULL) { + close(fd); + return (ISC_FALSE); + } + + isc_buffer_init(&buf, data, req_len); + isc_buffer_putuint32(&buf, SSU_EXTERNAL_VERSION); + isc_buffer_putuint32(&buf, req_len); + + /* Strings must be null-terminated */ + isc_buffer_putstr(&buf, b_signer); + isc_buffer_putuint8(&buf, 0); + isc_buffer_putstr(&buf, b_name); + isc_buffer_putuint8(&buf, 0); + isc_buffer_putstr(&buf, b_addr); + isc_buffer_putuint8(&buf, 0); + isc_buffer_putstr(&buf, b_type); + isc_buffer_putuint8(&buf, 0); + isc_buffer_putstr(&buf, b_key); + isc_buffer_putuint8(&buf, 0); + + isc_buffer_putuint32(&buf, token_len); + if (tkey_token && token_len != 0) + isc_buffer_putmem(&buf, token_region.base, token_len); + + ENSURE(isc_buffer_availablelength(&buf) == 0); + + /* Send the request */ + ret = write(fd, data, req_len); + isc_mem_free(mctx, data); + if (ret != (ssize_t) req_len) { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(errno, strbuf, sizeof(strbuf)); + ssu_e_log(3, "ssu_external: unable to send request - %s", + strbuf); + close(fd); + return (ISC_FALSE); + } + + /* Receive the reply */ + ret = read(fd, &reply, sizeof(isc_uint32_t)); + if (ret != (ssize_t) sizeof(isc_uint32_t)) { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(errno, strbuf, sizeof(strbuf)); + ssu_e_log(3, "ssu_external: unable to receive reply - %s", + strbuf); + close(fd); + return (ISC_FALSE); + } + + close(fd); + + reply = ntohl(reply); + + if (reply == 0) { + ssu_e_log(3, "ssu_external: denied external auth for '%s'", + b_name); + return (ISC_FALSE); + } else if (reply == 1) { + ssu_e_log(3, "ssu_external: allowed external auth for '%s'", + b_name); + return (ISC_TRUE); + } + + ssu_e_log(3, "ssu_external: invalid reply 0x%08x", reply); + + return (ISC_FALSE); +} diff --git a/lib/dns/stats.c b/lib/dns/stats.c index b73a3b3..cb46bf5 100644 --- a/lib/dns/stats.c +++ b/lib/dns/stats.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: stats.c,v 1.16.118.2 2009-01-29 23:47:44 tbox Exp $ */ +/* $Id: stats.c,v 1.18 2009-01-27 23:47:54 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/time.c b/lib/dns/time.c index bd8cdc3..3f55f19 100644 --- a/lib/dns/time.c +++ b/lib/dns/time.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: time.c,v 1.31.332.4 2010-04-21 23:48:05 tbox Exp $ */ +/* $Id: time.c,v 1.35 2010-04-21 23:51:22 tbox Exp $ */ /*! \file */ diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c index 7107dd5..a861ee3 100644 --- a/lib/dns/tkey.c +++ b/lib/dns/tkey.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -16,7 +16,7 @@ */ /* - * $Id: tkey.c,v 1.90.118.4 2010-12-09 01:12:55 marka Exp $ + * $Id: tkey.c,v 1.100 2011-01-08 23:47:01 tbox Exp $ */ /*! \file */ #include @@ -99,6 +99,7 @@ dns_tkeyctx_create(isc_mem_t *mctx, isc_entropy_t *ectx, dns_tkeyctx_t **tctxp) tctx->dhkey = NULL; tctx->domain = NULL; tctx->gsscred = NULL; + tctx->gssapi_keytab = NULL; *tctxp = tctx; return (ISC_R_SUCCESS); @@ -121,6 +122,9 @@ dns_tkeyctx_destroy(dns_tkeyctx_t **tctxp) { dns_name_free(tctx->domain, mctx); isc_mem_put(mctx, tctx->domain, sizeof(dns_name_t)); } + if (tctx->gssapi_keytab != NULL) { + isc_mem_free(mctx, tctx->gssapi_keytab); + } if (tctx->gsscred != NULL) dst_gssapi_releasecred(&tctx->gsscred); isc_entropy_detach(&tctx->ectx); @@ -430,8 +434,17 @@ process_gsstkey(dns_name_t *name, dns_rdata_tkey_t *tkeyin, isc_buffer_t *outtoken = NULL; gss_ctx_id_t gss_ctx = NULL; - if (tctx->gsscred == NULL) + /* + * You have to define either a gss credential (principal) to + * accept with tkey-gssapi-credential, or you have to + * configure a specific keytab (with tkey-gssapi-keytab) in + * order to use gsstkey + */ + if (tctx->gsscred == NULL && tctx->gssapi_keytab == NULL) { + tkey_log("process_gsstkey(): no tkey-gssapi-credential " + "or tkey-gssapi-keytab configured"); return (ISC_R_NOPERM); + } if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPI_NAME) && !dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPIMS_NAME)) { @@ -454,7 +467,11 @@ process_gsstkey(dns_name_t *name, dns_rdata_tkey_t *tkeyin, dns_fixedname_init(&principal); - result = dst_gssapi_acceptctx(tctx->gsscred, &intoken, + /* + * Note that tctx->gsscred may be NULL if tctx->gssapi_keytab is set + */ + result = dst_gssapi_acceptctx(tctx->gsscred, tctx->gssapi_keytab, + &intoken, &outtoken, &gss_ctx, dns_fixedname_name(&principal), tctx->mctx); @@ -479,7 +496,8 @@ process_gsstkey(dns_name_t *name, dns_rdata_tkey_t *tkeyin, #endif isc_uint32_t expire; - RETERR(dst_key_fromgssapi(name, gss_ctx, ring->mctx, &dstkey)); + RETERR(dst_key_fromgssapi(name, gss_ctx, ring->mctx, + &dstkey, &intoken)); /* * Limit keys to 1 hour or the context's lifetime whichever * is smaller. @@ -734,8 +752,7 @@ dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx, } isc_buffer_init(&b, randomtext, sizeof(randomtext)); isc_buffer_add(&b, sizeof(randomtext)); - result = dns_name_fromtext(keyname, &b, NULL, - ISC_FALSE, NULL); + result = dns_name_fromtext(keyname, &b, NULL, 0, NULL); if (result != ISC_R_SUCCESS) goto failure; } @@ -985,7 +1002,8 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name, isc_result_t dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname, isc_buffer_t *intoken, isc_uint32_t lifetime, - gss_ctx_id_t *context, isc_boolean_t win2k) + gss_ctx_id_t *context, isc_boolean_t win2k, + isc_mem_t *mctx, char **err_message) { dns_rdata_tkey_t tkey; isc_result_t result; @@ -999,9 +1017,11 @@ dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname, REQUIRE(name != NULL); REQUIRE(gname != NULL); REQUIRE(context != NULL); + REQUIRE(mctx != NULL); isc_buffer_init(&token, array, sizeof(array)); - result = dst_gssapi_initctx(gname, NULL, &token, context); + result = dst_gssapi_initctx(gname, NULL, &token, context, + mctx, err_message); if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) return (result); @@ -1218,7 +1238,7 @@ isc_result_t dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, dns_name_t *gname, gss_ctx_id_t *context, isc_buffer_t *outtoken, dns_tsigkey_t **outkey, - dns_tsig_keyring_t *ring) + dns_tsig_keyring_t *ring, char **err_message) { dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; dns_name_t *tkeyname; @@ -1232,6 +1252,7 @@ dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, REQUIRE(qmsg != NULL); REQUIRE(rmsg != NULL); REQUIRE(gname != NULL); + REQUIRE(ring != NULL); if (outkey != NULL) REQUIRE(*outkey == NULL); @@ -1268,10 +1289,11 @@ dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, isc_buffer_init(outtoken, array, sizeof(array)); isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); - RETERR(dst_gssapi_initctx(gname, &intoken, outtoken, context)); + RETERR(dst_gssapi_initctx(gname, &intoken, outtoken, context, + ring->mctx, err_message)); RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, - &dstkey)); + &dstkey, NULL)); RETERR(dns_tsigkey_createfromkey(tkeyname, DNS_TSIG_GSSAPI_NAME, dstkey, ISC_FALSE, NULL, @@ -1349,7 +1371,7 @@ isc_result_t dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, dns_name_t *server, gss_ctx_id_t *context, dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring, - isc_boolean_t win2k) + isc_boolean_t win2k, char **err_message) { dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; dns_name_t *tkeyname; @@ -1393,12 +1415,13 @@ dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); isc_buffer_init(&outtoken, array, sizeof(array)); - result = dst_gssapi_initctx(server, &intoken, &outtoken, context); + result = dst_gssapi_initctx(server, &intoken, &outtoken, context, + ring->mctx, err_message); if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) return (result); RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, - &dstkey)); + &dstkey, NULL)); /* * XXXSRA This seems confused. If we got CONTINUE from initctx, diff --git a/lib/dns/tsec.c b/lib/dns/tsec.c new file mode 100644 index 0000000..b7ed777 --- /dev/null +++ b/lib/dns/tsec.c @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: tsec.c,v 1.7 2010-12-09 00:54:34 marka Exp $ */ + +#include + +#include + +#include +#include +#include + +#include + +#define DNS_TSEC_MAGIC ISC_MAGIC('T', 's', 'e', 'c') +#define DNS_TSEC_VALID(t) ISC_MAGIC_VALID(t, DNS_TSEC_MAGIC) + +/*% + * DNS Transaction Security object. We assume this is not shared by + * multiple threads, and so the structure does not contain a lock. + */ +struct dns_tsec { + unsigned int magic; + dns_tsectype_t type; + isc_mem_t *mctx; + union { + dns_tsigkey_t *tsigkey; + dst_key_t *key; + } ukey; +}; + +isc_result_t +dns_tsec_create(isc_mem_t *mctx, dns_tsectype_t type, dst_key_t *key, + dns_tsec_t **tsecp) +{ + isc_result_t result; + dns_tsec_t *tsec; + dns_tsigkey_t *tsigkey = NULL; + dns_name_t *algname; + + REQUIRE(mctx != NULL); + REQUIRE(tsecp != NULL && *tsecp == NULL); + + tsec = isc_mem_get(mctx, sizeof(*tsec)); + if (tsec == NULL) + return (ISC_R_NOMEMORY); + + tsec->type = type; + tsec->mctx = mctx; + + switch (type) { + case dns_tsectype_tsig: + switch (dst_key_alg(key)) { + case DST_ALG_HMACMD5: + algname = dns_tsig_hmacmd5_name; + break; + case DST_ALG_HMACSHA1: + algname = dns_tsig_hmacsha1_name; + break; + case DST_ALG_HMACSHA224: + algname = dns_tsig_hmacsha224_name; + break; + case DST_ALG_HMACSHA256: + algname = dns_tsig_hmacsha256_name; + break; + case DST_ALG_HMACSHA384: + algname = dns_tsig_hmacsha384_name; + break; + case DST_ALG_HMACSHA512: + algname = dns_tsig_hmacsha512_name; + break; + default: + isc_mem_put(mctx, tsec, sizeof(*tsec)); + return (DNS_R_BADALG); + } + result = dns_tsigkey_createfromkey(dst_key_name(key), + algname, key, ISC_FALSE, + NULL, 0, 0, mctx, NULL, + &tsigkey); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, tsec, sizeof(*tsec)); + return (result); + } + tsec->ukey.tsigkey = tsigkey; + break; + case dns_tsectype_sig0: + tsec->ukey.key = key; + break; + default: + INSIST(0); + } + + tsec->magic = DNS_TSEC_MAGIC; + + *tsecp = tsec; + return (ISC_R_SUCCESS); +} + +void +dns_tsec_destroy(dns_tsec_t **tsecp) { + dns_tsec_t *tsec; + + REQUIRE(tsecp != NULL && *tsecp != NULL); + tsec = *tsecp; + REQUIRE(DNS_TSEC_VALID(tsec)); + + switch (tsec->type) { + case dns_tsectype_tsig: + dns_tsigkey_detach(&tsec->ukey.tsigkey); + break; + case dns_tsectype_sig0: + dst_key_free(&tsec->ukey.key); + break; + default: + INSIST(0); + } + + tsec->magic = 0; + isc_mem_put(tsec->mctx, tsec, sizeof(*tsec)); + + *tsecp = NULL; +} + +dns_tsectype_t +dns_tsec_gettype(dns_tsec_t *tsec) { + REQUIRE(DNS_TSEC_VALID(tsec)); + + return (tsec->type); +} + +void +dns_tsec_getkey(dns_tsec_t *tsec, void *keyp) { + REQUIRE(DNS_TSEC_VALID(tsec)); + REQUIRE(keyp != NULL); + + switch (tsec->type) { + case dns_tsectype_tsig: + dns_tsigkey_attach(tsec->ukey.tsigkey, (dns_tsigkey_t **)keyp); + break; + case dns_tsectype_sig0: + *(dst_key_t **)keyp = tsec->ukey.key; + break; + default: + INSIST(0); + } +} diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c index 65d32dc..cec5222 100644 --- a/lib/dns/tsig.c +++ b/lib/dns/tsig.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -16,7 +16,7 @@ */ /* - * $Id: tsig.c,v 1.136.18.5 2010-12-09 01:12:55 marka Exp $ + * $Id: tsig.c,v 1.147 2011-01-11 23:47:13 tbox Exp $ */ /*! \file */ #include @@ -91,31 +91,6 @@ static dns_name_t gsstsig = { }; LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapi_name = &gsstsig; -static void -remove_fromring(dns_tsigkey_t *tkey) { - if (tkey->generated) { - ISC_LIST_UNLINK(tkey->ring->lru, tkey, link); - tkey->ring->generated--; - } - (void)dns_rbt_deletename(tkey->ring->keys, &tkey->name, ISC_FALSE); -} - -static void -adjust_lru(dns_tsigkey_t *tkey) { - if (tkey->generated) { - RWLOCK(&tkey->ring->lock, isc_rwlocktype_write); - /* - * We may have been removed from the LRU list between - * removing the read lock and aquiring the write lock. - */ - if (ISC_LINK_LINKED(tkey, link)) { - ISC_LIST_UNLINK(tkey->ring->lru, tkey, link); - ISC_LIST_APPEND(tkey->ring->lru, tkey, link); - } - RWUNLOCK(&tkey->ring->lock, isc_rwlocktype_write); - } -} - /* * Since Microsoft doesn't follow its own standard, we will use this * alternate name as a second guess. @@ -228,8 +203,10 @@ tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) { else strcpy(namestr, ""); - if (key != NULL && key->generated) + if (key != NULL && key->generated && key->creator) dns_name_format(key->creator, creatorstr, sizeof(creatorstr)); + else + strcpy(creatorstr, ""); va_start(ap, fmt); vsnprintf(message, sizeof(message), fmt, ap); @@ -245,6 +222,71 @@ tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) { level, "tsig key '%s': %s", namestr, message); } +static void +remove_fromring(dns_tsigkey_t *tkey) { + if (tkey->generated) { + ISC_LIST_UNLINK(tkey->ring->lru, tkey, link); + tkey->ring->generated--; + } + (void)dns_rbt_deletename(tkey->ring->keys, &tkey->name, ISC_FALSE); +} + +static void +adjust_lru(dns_tsigkey_t *tkey) { + if (tkey->generated) { + RWLOCK(&tkey->ring->lock, isc_rwlocktype_write); + /* + * We may have been removed from the LRU list between + * removing the read lock and aquiring the write lock. + */ + if (ISC_LINK_LINKED(tkey, link)) { + ISC_LIST_UNLINK(tkey->ring->lru, tkey, link); + ISC_LIST_APPEND(tkey->ring->lru, tkey, link); + } + RWUNLOCK(&tkey->ring->lock, isc_rwlocktype_write); + } +} + +/* + * A supplemental routine just to add a key to ring. Note that reference + * counter should be counted separately because we may be adding the key + * as part of creation of the key, in which case the reference counter was + * already initialized. Also note we don't need RWLOCK for the reference + * counter: it's protected by a separate lock. + */ +static isc_result_t +keyring_add(dns_tsig_keyring_t *ring, dns_name_t *name, + dns_tsigkey_t *tkey) +{ + isc_result_t result; + + RWLOCK(&ring->lock, isc_rwlocktype_write); + ring->writecount++; + + /* + * Do on the fly cleaning. Find some nodes we might not + * want around any more. + */ + if (ring->writecount > 10) { + cleanup_ring(ring); + ring->writecount = 0; + } + + result = dns_rbt_addname(ring->keys, name, tkey); + if (tkey->generated) { + /* + * Add the new key to the LRU list and remove the least + * recently used key if there are too many keys on the list. + */ + ISC_LIST_INITANDAPPEND(ring->lru, tkey, link); + if (ring->generated++ > ring->maxgenerated) + remove_fromring(ISC_LIST_HEAD(ring->lru)); + } + RWUNLOCK(&ring->lock, isc_rwlocktype_write); + + return (result); +} + isc_result_t dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, dst_key_t *dstkey, isc_boolean_t generated, @@ -363,7 +405,7 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, tkey->ring = ring; if (key != NULL) - refs++; + refs = 1; if (ring != NULL) refs++; ret = isc_refcount_init(&tkey->refs, refs); @@ -379,36 +421,9 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, tkey->magic = TSIG_MAGIC; if (ring != NULL) { - RWLOCK(&ring->lock, isc_rwlocktype_write); - ring->writecount++; - - /* - * Do on the fly cleaning. Find some nodes we might not - * want around any more. - */ - if (ring->writecount > 10) { - cleanup_ring(ring); - ring->writecount = 0; - } - - ret = dns_rbt_addname(ring->keys, name, tkey); - if (ret != ISC_R_SUCCESS) { - RWUNLOCK(&ring->lock, isc_rwlocktype_write); + ret = keyring_add(ring, name, tkey); + if (ret != ISC_R_SUCCESS) goto cleanup_refs; - } - - if (tkey->generated) { - /* - * Add the new key to the LRU list and remove the - * least recently used key if there are too many - * keys on the list. - */ - ISC_LIST_INITANDAPPEND(ring->lru, tkey, link); - if (ring->generated++ > ring->maxgenerated) - remove_fromring(ISC_LIST_HEAD(ring->lru)); - } - - RWUNLOCK(&ring->lock, isc_rwlocktype_write); } /* @@ -424,6 +439,7 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm, "the key '%s' is too short to be secure", namestr); } + if (key != NULL) *key = tkey; @@ -512,6 +528,184 @@ cleanup_ring(dns_tsig_keyring_t *ring) } } +static void +destroyring(dns_tsig_keyring_t *ring) { + dns_rbt_destroy(&ring->keys); + isc_rwlock_destroy(&ring->lock); + isc_mem_putanddetach(&ring->mctx, ring, sizeof(dns_tsig_keyring_t)); +} + +static unsigned int +dst_alg_fromname(dns_name_t *algorithm) { + if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) { + return (DST_ALG_HMACMD5); + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) { + return (DST_ALG_HMACSHA1); + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) { + return (DST_ALG_HMACSHA224); + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) { + return (DST_ALG_HMACSHA256); + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) { + return (DST_ALG_HMACSHA384); + } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) { + return (DST_ALG_HMACSHA512); + } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME)) { + return (DST_ALG_GSSAPI); + } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) { + return (DST_ALG_GSSAPI); + } else + return (0); +} + +static isc_result_t +restore_key(dns_tsig_keyring_t *ring, isc_stdtime_t now, FILE *fp) { + dst_key_t *dstkey = NULL; + char namestr[1024]; + char creatorstr[1024]; + char algorithmstr[1024]; + char keystr[4096]; + unsigned int inception, expire; + int n; + isc_buffer_t b; + dns_name_t *name, *creator, *algorithm; + dns_fixedname_t fname, fcreator, falgorithm; + isc_result_t result; + unsigned int dstalg; + + n = fscanf(fp, "%1023s %1023s %u %u %1023s %4095s\n", namestr, + creatorstr, &inception, &expire, algorithmstr, keystr); + if (n == EOF) + return (ISC_R_NOMORE); + if (n != 6) + return (ISC_R_FAILURE); + + if (isc_serial_lt(expire, now)) + return (DNS_R_EXPIRED); + + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + isc_buffer_init(&b, namestr, strlen(namestr)); + isc_buffer_add(&b, strlen(namestr)); + result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) + return (result); + + dns_fixedname_init(&fcreator); + creator = dns_fixedname_name(&fcreator); + isc_buffer_init(&b, creatorstr, strlen(creatorstr)); + isc_buffer_add(&b, strlen(creatorstr)); + result = dns_name_fromtext(creator, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) + return (result); + + dns_fixedname_init(&falgorithm); + algorithm = dns_fixedname_name(&falgorithm); + isc_buffer_init(&b, algorithmstr, strlen(algorithmstr)); + isc_buffer_add(&b, strlen(algorithmstr)); + result = dns_name_fromtext(algorithm, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) + return (result); + + dstalg = dst_alg_fromname(algorithm); + if (dstalg == 0) + return (DNS_R_BADALG); + + result = dst_key_restore(name, dstalg, DNS_KEYOWNER_ENTITY, + DNS_KEYPROTO_DNSSEC, dns_rdataclass_in, + ring->mctx, keystr, &dstkey); + if (result != ISC_R_SUCCESS) + return (result); + + result = dns_tsigkey_createfromkey(name, algorithm, dstkey, + ISC_TRUE, creator, inception, + expire, ring->mctx, ring, NULL); + if (result != ISC_R_SUCCESS && dstkey != NULL) + dst_key_free(&dstkey); + return (result); +} + +static void +dump_key(dns_tsigkey_t *tkey, FILE *fp) +{ + char *buffer = NULL; + int length = 0; + char namestr[DNS_NAME_FORMATSIZE]; + char creatorstr[DNS_NAME_FORMATSIZE]; + char algorithmstr[DNS_NAME_FORMATSIZE]; + isc_result_t result; + + dns_name_format(&tkey->name, namestr, sizeof(namestr)); + dns_name_format(tkey->creator, creatorstr, sizeof(creatorstr)); + dns_name_format(tkey->algorithm, algorithmstr, sizeof(algorithmstr)); + result = dst_key_dump(tkey->key, tkey->mctx, &buffer, &length); + if (result == ISC_R_SUCCESS) + fprintf(fp, "%s %s %u %u %s %.*s\n", namestr, creatorstr, + tkey->inception, tkey->expire, algorithmstr, + length, buffer); + if (buffer != NULL) + isc_mem_put(tkey->mctx, buffer, length); +} + +isc_result_t +dns_tsigkeyring_dumpanddetach(dns_tsig_keyring_t **ringp, FILE *fp) { + isc_result_t result; + dns_rbtnodechain_t chain; + dns_name_t foundname; + dns_fixedname_t fixedorigin; + dns_name_t *origin; + isc_stdtime_t now; + dns_rbtnode_t *node; + dns_tsigkey_t *tkey; + dns_tsig_keyring_t *ring; + unsigned int references; + + REQUIRE(ringp != NULL && *ringp != NULL); + + ring = *ringp; + *ringp = NULL; + + RWLOCK(&ring->lock, isc_rwlocktype_write); + INSIST(ring->references > 0); + ring->references--; + references = ring->references; + RWUNLOCK(&ring->lock, isc_rwlocktype_write); + + if (references != 0) + return (DNS_R_CONTINUE); + + isc_stdtime_get(&now); + dns_name_init(&foundname, NULL); + dns_fixedname_init(&fixedorigin); + origin = dns_fixedname_name(&fixedorigin); + dns_rbtnodechain_init(&chain, ring->mctx); + result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, + origin); + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + goto destroy; + } + + for (;;) { + node = NULL; + dns_rbtnodechain_current(&chain, &foundname, origin, &node); + tkey = node->data; + if (tkey != NULL && tkey->generated && tkey->expire >= now) + dump_key(tkey, fp); + result = dns_rbtnodechain_next(&chain, &foundname, + origin); + if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { + dns_rbtnodechain_invalidate(&chain); + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + goto destroy; + } + } + + destroy: + destroyring(ring); + return (result); +} + isc_result_t dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm, unsigned char *secret, int length, isc_boolean_t generated, @@ -1589,14 +1783,43 @@ dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) { ring->maxgenerated = DNS_TSIG_MAXGENERATEDKEYS; ISC_LIST_INIT(ring->lru); isc_mem_attach(mctx, &ring->mctx); + ring->references = 1; *ringp = ring; return (ISC_R_SUCCESS); } +isc_result_t +dns_tsigkeyring_add(dns_tsig_keyring_t *ring, dns_name_t *name, + dns_tsigkey_t *tkey) +{ + isc_result_t result; + + result = keyring_add(ring, name, tkey); + if (result == ISC_R_SUCCESS) + isc_refcount_increment(&tkey->refs, NULL); + + return (result); +} + void -dns_tsigkeyring_destroy(dns_tsig_keyring_t **ringp) { +dns_tsigkeyring_attach(dns_tsig_keyring_t *source, dns_tsig_keyring_t **target) +{ + REQUIRE(source != NULL); + REQUIRE(target != NULL && *target == NULL); + + RWLOCK(&source->lock, isc_rwlocktype_write); + INSIST(source->references > 0); + source->references++; + INSIST(source->references > 0); + *target = source; + RWUNLOCK(&source->lock, isc_rwlocktype_write); +} + +void +dns_tsigkeyring_detach(dns_tsig_keyring_t **ringp) { dns_tsig_keyring_t *ring; + unsigned int references; REQUIRE(ringp != NULL); REQUIRE(*ringp != NULL); @@ -1604,7 +1827,27 @@ dns_tsigkeyring_destroy(dns_tsig_keyring_t **ringp) { ring = *ringp; *ringp = NULL; - dns_rbt_destroy(&ring->keys); - isc_rwlock_destroy(&ring->lock); - isc_mem_putanddetach(&ring->mctx, ring, sizeof(dns_tsig_keyring_t)); + RWLOCK(&ring->lock, isc_rwlocktype_write); + INSIST(ring->references > 0); + ring->references--; + references = ring->references; + RWUNLOCK(&ring->lock, isc_rwlocktype_write); + + if (references == 0) + destroyring(ring); +} + +void +dns_keyring_restore(dns_tsig_keyring_t *ring, FILE *fp) { + isc_stdtime_t now; + isc_result_t result; + + isc_stdtime_get(&now); + do { + result = restore_key(ring, now, fp); + if (result == ISC_R_NOMORE) + return; + if (result == DNS_R_BADALG || result == DNS_R_EXPIRED) + result = ISC_R_SUCCESS; + } while (result == ISC_R_SUCCESS); } diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 79c8798..6c0d38d 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: validator.c,v 1.164.12.23.4.3 2011-06-21 20:13:23 each Exp $ */ +/* $Id: validator.c,v 1.197.40.3 2011-06-21 20:15:54 each Exp $ */ #include @@ -28,17 +28,17 @@ #include #include -#include #include +#include #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -255,9 +255,17 @@ dlv_algorithm_supported(dns_validator_t *val) { dlv.algorithm)) continue; +#ifdef HAVE_OPENSSL_GOST + if (dlv.digest_type != DNS_DSDIGEST_SHA256 && + dlv.digest_type != DNS_DSDIGEST_SHA1 && + dlv.digest_type != DNS_DSDIGEST_GOST) + continue; +#else if (dlv.digest_type != DNS_DSDIGEST_SHA256 && dlv.digest_type != DNS_DSDIGEST_SHA1) continue; +#endif + return (ISC_TRUE); } @@ -383,7 +391,7 @@ isdelegation(dns_name_t *name, dns_rdataset_t *rdataset, } /*% - * We have been asked to to look for a key. + * We have been asked to look for a key. * If found resume the validation process. * If not found fail the validation process. */ @@ -582,7 +590,8 @@ dsfetched2(isc_task_t *task, isc_event_t *event) { if (isdelegation(tname, &val->frdataset, eresult)) { if (val->mustbesecure) { validator_log(val, ISC_LOG_WARNING, - "must be secure failure"); + "must be secure failure, no DS" + " and this is a delegation"); validator_done(val, DNS_R_MUSTBESECURE); } else if (val->view->dlv == NULL || DLVTRIED(val)) { markanswer(val, "dsfetched2"); @@ -1089,7 +1098,7 @@ nsec3noexistnodata(dns_validator_t *val, dns_name_t* name, if (ns && !soa) { if (!atparent) { /* - * This NSEC record is from somewhere + * This NSEC3 record is from somewhere * higher in the DNS, and at the * parent of a delegation. It can not * be legitimately used here. @@ -1100,7 +1109,7 @@ nsec3noexistnodata(dns_validator_t *val, dns_name_t* name, } } else if (atparent && ns && soa) { /* - * This NSEC record is from the child. + * This NSEC3 record is from the child. * It can not be legitimately used here. */ validator_log(val, ISC_LOG_DEBUG(3), @@ -1505,8 +1514,11 @@ create_fetch(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, if (dns_rdataset_isassociated(&val->fsigrdataset)) dns_rdataset_disassociate(&val->fsigrdataset); - if (check_deadlock(val, name, type, NULL, NULL)) + if (check_deadlock(val, name, type, NULL, NULL)) { + validator_log(val, ISC_LOG_DEBUG(3), + "deadlock found (create_fetch)"); return (DNS_R_NOVALIDSIG); + } validator_logcreate(val, name, type, caller, "fetch"); return (dns_resolver_createfetch(val->view->resolver, name, type, @@ -1528,8 +1540,11 @@ create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, { isc_result_t result; - if (check_deadlock(val, name, type, rdataset, sigrdataset)) + if (check_deadlock(val, name, type, rdataset, sigrdataset)) { + validator_log(val, ISC_LOG_DEBUG(3), + "deadlock found (create_validator)"); return (DNS_R_NOVALIDSIG); + } validator_logcreate(val, name, type, caller, "validator"); result = dns_validator_create(val->view, name, type, @@ -1768,16 +1783,23 @@ compute_keytag(dns_rdata_t *rdata, dns_rdata_dnskey_t *key) { */ static isc_boolean_t isselfsigned(dns_validator_t *val) { + dns_fixedname_t fixed; dns_rdataset_t *rdataset, *sigrdataset; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_t sigrdata = DNS_RDATA_INIT; dns_rdata_dnskey_t key; dns_rdata_rrsig_t sig; dns_keytag_t keytag; + dns_name_t *name; isc_result_t result; + dst_key_t *dstkey; + isc_mem_t *mctx; + isc_boolean_t answer = ISC_FALSE; rdataset = val->event->rdataset; sigrdataset = val->event->sigrdataset; + name = val->event->name; + mctx = val->view->mctx; INSIST(rdataset->type == dns_rdatatype_dnskey); @@ -1799,12 +1821,31 @@ isselfsigned(dns_validator_t *val) { result = dns_rdata_tostruct(&sigrdata, &sig, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); - if (sig.algorithm == key.algorithm && - sig.keyid == keytag) - return (ISC_TRUE); + if (sig.algorithm != key.algorithm || + sig.keyid != keytag || + !dns_name_equal(name, &sig.signer)) + continue; + + dstkey = NULL; + result = dns_dnssec_keyfromrdata(name, &rdata, mctx, + &dstkey); + if (result != ISC_R_SUCCESS) + continue; + + result = dns_dnssec_verify2(name, rdataset, dstkey, + ISC_TRUE, mctx, &sigrdata, + dns_fixedname_name(&fixed)); + dst_key_free(&dstkey); + if (result != ISC_R_SUCCESS) + continue; + if ((key.flags & DNS_KEYFLAG_REVOKE) == 0) { + answer = ISC_TRUE; + continue; + } + dns_view_untrust(val->view, name, &key, mctx); } } - return (ISC_FALSE); + return (answer); } /*% @@ -1946,6 +1987,8 @@ validate(dns_validator_t *val, isc_boolean_t resume) { break; } val->key = dns_keynode_key(val->keynode); + if (val->key == NULL) + break; } else { if (get_dst_key(val, val->siginfo, val->keyset) != ISC_R_SUCCESS) @@ -1962,8 +2005,6 @@ validate(dns_validator_t *val, isc_boolean_t resume) { isc_stdtime_get(&now); ttl = ISC_MIN(event->rdataset->ttl, val->siginfo->timeexpire - now); - if (val->keyset != NULL) - ttl = ISC_MIN(ttl, val->keyset->ttl); event->rdataset->ttl = ttl; event->sigrdataset->ttl = ttl; } @@ -1992,7 +2033,8 @@ validate(dns_validator_t *val, isc_boolean_t resume) { } else if (result == ISC_R_SUCCESS) { marksecure(event); validator_log(val, ISC_LOG_DEBUG(3), - "marking as secure"); + "marking as secure, " + "noqname proof not needed"); return (result); } else { validator_log(val, ISC_LOG_DEBUG(3), @@ -2013,25 +2055,102 @@ validate(dns_validator_t *val, isc_boolean_t resume) { } /*% + * Check whether this DNSKEY (keyrdata) signed the DNSKEY RRset + * (val->event->rdataset). + */ +static isc_result_t +checkkey(dns_validator_t *val, dns_rdata_t *keyrdata, isc_uint16_t keyid, + dns_secalg_t algorithm) +{ + dns_rdata_rrsig_t sig; + dst_key_t *dstkey = NULL; + isc_result_t result; + + for (result = dns_rdataset_first(val->event->sigrdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(val->event->sigrdataset)) + { + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_rdataset_current(val->event->sigrdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &sig, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (keyid != sig.keyid || algorithm != sig.algorithm) + continue; + if (dstkey == NULL) { + result = dns_dnssec_keyfromrdata(val->event->name, + keyrdata, + val->view->mctx, + &dstkey); + if (result != ISC_R_SUCCESS) + /* + * This really shouldn't happen, but... + */ + continue; + } + result = verify(val, dstkey, &rdata, sig.keyid); + if (result == ISC_R_SUCCESS) + break; + } + if (dstkey != NULL) + dst_key_free(&dstkey); + return (result); +} + +/*% + * Find the DNSKEY that corresponds to the DS. + */ +static isc_result_t +keyfromds(dns_validator_t *val, dns_rdataset_t *rdataset, dns_rdata_t *dsrdata, + isc_uint8_t digest, isc_uint16_t keyid, dns_secalg_t algorithm, + dns_rdata_t *keyrdata) +{ + dns_keytag_t keytag; + dns_rdata_dnskey_t key; + isc_result_t result; + unsigned char dsbuf[DNS_DS_BUFFERSIZE]; + + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) + { + dns_rdata_t newdsrdata = DNS_RDATA_INIT; + + dns_rdata_reset(keyrdata); + dns_rdataset_current(rdataset, keyrdata); + result = dns_rdata_tostruct(keyrdata, &key, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + keytag = compute_keytag(keyrdata, &key); + if (keyid != keytag || algorithm != key.algorithm) + continue; + dns_rdata_reset(&newdsrdata); + result = dns_ds_buildrdata(val->event->name, keyrdata, digest, + dsbuf, &newdsrdata); + if (result != ISC_R_SUCCESS) { + validator_log(val, ISC_LOG_DEBUG(3), + "dns_ds_buildrdata() -> %s", + dns_result_totext(result)); + continue; + } + if (dns_rdata_compare(dsrdata, &newdsrdata) == 0) + break; + } + return (result); +} + +/*% * Validate the DNSKEY RRset by looking for a DNSKEY that matches a * DLV record and that also verifies the DNSKEY RRset. */ static isc_result_t dlv_validatezonekey(dns_validator_t *val) { - dns_keytag_t keytag; dns_rdata_dlv_t dlv; - dns_rdata_dnskey_t key; - dns_rdata_rrsig_t sig; dns_rdata_t dlvrdata = DNS_RDATA_INIT; dns_rdata_t keyrdata = DNS_RDATA_INIT; - dns_rdata_t newdsrdata = DNS_RDATA_INIT; - dns_rdata_t sigrdata = DNS_RDATA_INIT; dns_rdataset_t trdataset; - dst_key_t *dstkey; isc_boolean_t supported_algorithm; isc_result_t result; - unsigned char dsbuf[DNS_DS_BUFFERSIZE]; - isc_uint8_t digest_type; + char digest_types[256]; validator_log(val, ISC_LOG_DEBUG(3), "dlv_validatezonekey"); @@ -2048,7 +2167,7 @@ dlv_validatezonekey(dns_validator_t *val) { * need to ignore DNS_DSDIGEST_SHA1 if a DNS_DSDIGEST_SHA256 * is present. */ - digest_type = DNS_DSDIGEST_SHA1; + memset(digest_types, 1, sizeof(digest_types)); for (result = dns_rdataset_first(&val->dlv); result == ISC_R_SUCCESS; result = dns_rdataset_next(&val->dlv)) { @@ -2064,7 +2183,7 @@ dlv_validatezonekey(dns_validator_t *val) { if (dlv.digest_type == DNS_DSDIGEST_SHA256 && dlv.length == ISC_SHA256_DIGESTLENGTH) { - digest_type = DNS_DSDIGEST_SHA256; + digest_types[DNS_DSDIGEST_SHA1] = 0; break; } } @@ -2082,7 +2201,7 @@ dlv_validatezonekey(dns_validator_t *val) { dlv.digest_type)) continue; - if (dlv.digest_type != digest_type) + if (digest_types[dlv.digest_type] == 0) continue; if (!dns_resolver_algorithm_supported(val->view->resolver, @@ -2095,70 +2214,27 @@ dlv_validatezonekey(dns_validator_t *val) { dns_rdataset_init(&trdataset); dns_rdataset_clone(val->event->rdataset, &trdataset); - for (result = dns_rdataset_first(&trdataset); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(&trdataset)) - { - dns_rdata_reset(&keyrdata); - dns_rdataset_current(&trdataset, &keyrdata); - result = dns_rdata_tostruct(&keyrdata, &key, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - keytag = compute_keytag(&keyrdata, &key); - if (dlv.key_tag != keytag || - dlv.algorithm != key.algorithm) - continue; - dns_rdata_reset(&newdsrdata); - result = dns_ds_buildrdata(val->event->name, - &keyrdata, dlv.digest_type, - dsbuf, &newdsrdata); - if (result != ISC_R_SUCCESS) { - validator_log(val, ISC_LOG_DEBUG(3), - "dns_ds_buildrdata() -> %s", - dns_result_totext(result)); - continue; - } - /* Covert to DLV */ - newdsrdata.type = dns_rdatatype_dlv; - if (dns_rdata_compare(&dlvrdata, &newdsrdata) == 0) - break; - } + /* + * Convert to DLV to DS and find matching DNSKEY. + */ + dlvrdata.type = dns_rdatatype_ds; + result = keyfromds(val, &trdataset, &dlvrdata, + dlv.digest_type, dlv.key_tag, + dlv.algorithm, &keyrdata); if (result != ISC_R_SUCCESS) { dns_rdataset_disassociate(&trdataset); validator_log(val, ISC_LOG_DEBUG(3), "no DNSKEY matching DLV"); continue; } + validator_log(val, ISC_LOG_DEBUG(3), "Found matching DLV record: checking for signature"); + /* + * Check that this DNSKEY signed the DNSKEY rrset. + */ + result = checkkey(val, &keyrdata, dlv.key_tag, dlv.algorithm); - for (result = dns_rdataset_first(val->event->sigrdataset); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(val->event->sigrdataset)) - { - dns_rdata_reset(&sigrdata); - dns_rdataset_current(val->event->sigrdataset, - &sigrdata); - result = dns_rdata_tostruct(&sigrdata, &sig, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - if (dlv.key_tag != sig.keyid || - dlv.algorithm != sig.algorithm) - continue; - dstkey = NULL; - result = dns_dnssec_keyfromrdata(val->event->name, - &keyrdata, - val->view->mctx, - &dstkey); - if (result != ISC_R_SUCCESS) - /* - * This really shouldn't happen, but... - */ - continue; - - result = verify(val, dstkey, &sigrdata, sig.keyid); - dst_key_free(&dstkey); - if (result == ISC_R_SUCCESS) - break; - } dns_rdataset_disassociate(&trdataset); if (result == ISC_R_SUCCESS) break; @@ -2167,12 +2243,13 @@ dlv_validatezonekey(dns_validator_t *val) { } if (result == ISC_R_SUCCESS) { marksecure(val->event); - validator_log(val, ISC_LOG_DEBUG(3), "marking as secure"); + validator_log(val, ISC_LOG_DEBUG(3), "marking as secure (dlv)"); return (result); } else if (result == ISC_R_NOMORE && !supported_algorithm) { if (val->mustbesecure) { validator_log(val, ISC_LOG_WARNING, - "must be secure failure"); + "must be secure failure," + "no supported algorithm/digest (dlv)"); return (DNS_R_MUSTBESECURE); } validator_log(val, ISC_LOG_DEBUG(3), @@ -2184,7 +2261,8 @@ dlv_validatezonekey(dns_validator_t *val) { } /*% - * Attempts positive response validation of an RRset containing zone keys. + * Attempts positive response validation of an RRset containing zone keys + * (i.e. a DNSKEY rrset). * * Returns: * \li ISC_R_SUCCESS Validation completed successfully @@ -2198,19 +2276,15 @@ validatezonekey(dns_validator_t *val) { dns_validatorevent_t *event; dns_rdataset_t trdataset; dns_rdata_t dsrdata = DNS_RDATA_INIT; - dns_rdata_t newdsrdata = DNS_RDATA_INIT; dns_rdata_t keyrdata = DNS_RDATA_INIT; dns_rdata_t sigrdata = DNS_RDATA_INIT; - unsigned char dsbuf[DNS_DS_BUFFERSIZE]; char namebuf[DNS_NAME_FORMATSIZE]; - dns_keytag_t keytag; dns_rdata_ds_t ds; - dns_rdata_dnskey_t key; dns_rdata_rrsig_t sig; dst_key_t *dstkey; isc_boolean_t supported_algorithm; isc_boolean_t atsep = ISC_FALSE; - isc_uint8_t digest_type; + char digest_types[256]; /* * Caller must be holding the validator lock. @@ -2259,8 +2333,7 @@ validatezonekey(dns_validator_t *val) { result = dns_keytable_findkeynode(val->keytable, val->event->name, sig.algorithm, - sig.keyid, - &keynode); + sig.keyid, &keynode); if (result == ISC_R_NOTFOUND && dns_keytable_finddeepestmatch(val->keytable, val->event->name, found) != ISC_R_SUCCESS) { @@ -2284,11 +2357,18 @@ validatezonekey(dns_validator_t *val) { while (result == ISC_R_SUCCESS) { dns_keynode_t *nextnode = NULL; dstkey = dns_keynode_key(keynode); + if (dstkey == NULL) { + dns_keytable_detachkeynode( + val->keytable, + &keynode); + break; + } result = verify(val, dstkey, &sigrdata, sig.keyid); if (result == ISC_R_SUCCESS) { - dns_keytable_detachkeynode(val->keytable, - &keynode); + dns_keytable_detachkeynode( + val->keytable, + &keynode); break; } result = dns_keytable_findnextkeynode( @@ -2318,8 +2398,8 @@ validatezonekey(dns_validator_t *val) { sizeof(namebuf)); validator_log(val, ISC_LOG_NOTICE, "unable to find a DNSKEY which verifies " - "the DNSKEY RRset and also matches one " - "of specified trusted-keys for '%s'", + "the DNSKEY RRset and also matches a " + "trusted key for '%s'", namebuf); validator_log(val, ISC_LOG_NOTICE, "please check the 'trusted-keys' for " @@ -2413,7 +2493,8 @@ validatezonekey(dns_validator_t *val) { if (val->dsset->trust < dns_trust_secure) { if (val->mustbesecure) { validator_log(val, ISC_LOG_WARNING, - "must be secure failure"); + "must be secure failure," + " insecure DS"); return (DNS_R_MUSTBESECURE); } if (val->view->dlv == NULL || DLVTRIED(val)) { @@ -2437,7 +2518,7 @@ validatezonekey(dns_validator_t *val) { * need to ignore DNS_DSDIGEST_SHA1 if a DNS_DSDIGEST_SHA256 * is present. */ - digest_type = DNS_DSDIGEST_SHA1; + memset(digest_types, 1, sizeof(digest_types)); for (result = dns_rdataset_first(val->dsset); result == ISC_R_SUCCESS; result = dns_rdataset_next(val->dsset)) { @@ -2453,7 +2534,7 @@ validatezonekey(dns_validator_t *val) { if (ds.digest_type == DNS_DSDIGEST_SHA256 && ds.length == ISC_SHA256_DIGESTLENGTH) { - digest_type = DNS_DSDIGEST_SHA256; + digest_types[DNS_DSDIGEST_SHA1] = 0; break; } } @@ -2471,7 +2552,7 @@ validatezonekey(dns_validator_t *val) { ds.digest_type)) continue; - if (ds.digest_type != digest_type) + if (digest_types[ds.digest_type] == 0) continue; if (!dns_resolver_algorithm_supported(val->view->resolver, @@ -2485,29 +2566,10 @@ validatezonekey(dns_validator_t *val) { dns_rdataset_clone(val->event->rdataset, &trdataset); /* - * Look for the KEY that matches the DS record. + * Find matching DNSKEY from DS. */ - for (result = dns_rdataset_first(&trdataset); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(&trdataset)) - { - dns_rdata_reset(&keyrdata); - dns_rdataset_current(&trdataset, &keyrdata); - result = dns_rdata_tostruct(&keyrdata, &key, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - keytag = compute_keytag(&keyrdata, &key); - if (ds.key_tag != keytag || - ds.algorithm != key.algorithm) - continue; - dns_rdata_reset(&newdsrdata); - result = dns_ds_buildrdata(val->event->name, - &keyrdata, ds.digest_type, - dsbuf, &newdsrdata); - if (result != ISC_R_SUCCESS) - continue; - if (dns_rdata_compare(&dsrdata, &newdsrdata) == 0) - break; - } + result = keyfromds(val, &trdataset, &dsrdata, ds.digest_type, + ds.key_tag, ds.algorithm, &keyrdata); if (result != ISC_R_SUCCESS) { dns_rdataset_disassociate(&trdataset); validator_log(val, ISC_LOG_DEBUG(3), @@ -2515,38 +2577,11 @@ validatezonekey(dns_validator_t *val) { continue; } - for (result = dns_rdataset_first(val->event->sigrdataset); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(val->event->sigrdataset)) - { - dns_rdata_reset(&sigrdata); - dns_rdataset_current(val->event->sigrdataset, - &sigrdata); - result = dns_rdata_tostruct(&sigrdata, &sig, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - if (ds.key_tag != sig.keyid || - ds.algorithm != sig.algorithm) - continue; - if (!dns_name_equal(val->event->name, &sig.signer)) { - validator_log(val, ISC_LOG_DEBUG(3), - "DNSKEY signer mismatch"); - continue; - } - dstkey = NULL; - result = dns_dnssec_keyfromrdata(val->event->name, - &keyrdata, - val->view->mctx, - &dstkey); - if (result != ISC_R_SUCCESS) - /* - * This really shouldn't happen, but... - */ - continue; - result = verify(val, dstkey, &sigrdata, sig.keyid); - dst_key_free(&dstkey); - if (result == ISC_R_SUCCESS) - break; - } + /* + * Check that this DNSKEY signed the DNSKEY rrset. + */ + result = checkkey(val, &keyrdata, ds.key_tag, ds.algorithm); + dns_rdataset_disassociate(&trdataset); if (result == ISC_R_SUCCESS) break; @@ -2555,20 +2590,24 @@ validatezonekey(dns_validator_t *val) { } if (result == ISC_R_SUCCESS) { marksecure(event); - validator_log(val, ISC_LOG_DEBUG(3), "marking as secure"); + validator_log(val, ISC_LOG_DEBUG(3), "marking as secure (DS)"); return (result); } else if (result == ISC_R_NOMORE && !supported_algorithm) { if (val->mustbesecure) { validator_log(val, ISC_LOG_WARNING, - "must be secure failure"); + "must be secure failure, " + "no supported algorithm/digest (DS)"); return (DNS_R_MUSTBESECURE); } validator_log(val, ISC_LOG_DEBUG(3), "no supported algorithm/digest (DS)"); markanswer(val, "validatezonekey (3)"); return (ISC_R_SUCCESS); - } else + } else { + validator_log(val, ISC_LOG_INFO, + "no valid signature found (DS)"); return (DNS_R_NOVALIDSIG); + } } /*% @@ -3094,9 +3133,7 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) { findnsec3proofs(val); if (FOUNDNOQNAME(val) && FOUNDCLOSEST(val)) { validator_log(val, ISC_LOG_DEBUG(3), - "noqname proof found"); - validator_log(val, ISC_LOG_DEBUG(3), - "marking as secure"); + "marking as secure, noqname proof found"); marksecure(val->event); return (ISC_R_SUCCESS); } else if (FOUNDOPTOUT(val) && @@ -3143,7 +3180,6 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) { marksecure(val->event); return (ISC_R_SUCCESS); } - findnsec3proofs(val); if (val->authfail != 0 && val->authcount == val->authfail) return (DNS_R_BROKENCHAIN); @@ -3345,7 +3381,8 @@ startfinddlvsep(dns_validator_t *val, dns_name_t *unsecure) { namebuf); if (dns_name_issubdomain(val->event->name, val->view->dlv)) { - validator_log(val, ISC_LOG_WARNING, "must be secure failure"); + validator_log(val, ISC_LOG_WARNING, "must be secure failure, " + " %s is under DLV (startfinddlvsep)", namebuf); return (DNS_R_MUSTBESECURE); } @@ -3397,10 +3434,12 @@ finddlvsep(dns_validator_t *val, isc_boolean_t resume) { INSIST(val->view->dlv != NULL); if (!resume) { - if (dns_name_issubdomain(val->event->name, val->view->dlv)) { + dns_name_format(val->event->name, namebuf, + sizeof(namebuf)); validator_log(val, ISC_LOG_WARNING, - "must be secure failure"); + "must be secure failure, " + "%s is under DLV (finddlvsep)", namebuf); return (DNS_R_MUSTBESECURE); } @@ -3468,8 +3507,11 @@ finddlvsep(dns_validator_t *val, isc_boolean_t resume) { return (result); return (DNS_R_WAIT); } - if (val->frdataset.trust < dns_trust_secure) + if (val->frdataset.trust < dns_trust_secure) { + validator_log(val, ISC_LOG_DEBUG(3), + "DLV not validated"); return (DNS_R_NOVALIDSIG); + } val->havedlvsep = ISC_TRUE; dns_rdataset_clone(&val->frdataset, &val->dlv); return (ISC_R_SUCCESS); @@ -3554,10 +3596,13 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) if (result == ISC_R_NOTFOUND) { if (val->mustbesecure) { validator_log(val, ISC_LOG_WARNING, - "must be secure failure"); + "must be secure failure, " + "not beneath secure root"); result = DNS_R_MUSTBESECURE; goto out; - } + } else + validator_log(val, ISC_LOG_DEBUG(3), + "not beneath secure root"); if (val->view->dlv == NULL || DLVTRIED(val)) { markanswer(val, "proveunsecure (1)"); return (ISC_R_SUCCESS); @@ -3577,7 +3622,7 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) /* * If we have a DS rdataset and it is secure then check if * the DS rdataset has a supported algorithm combination. - * If not this is a insecure delegation as far as this + * If not this is an insecure delegation as far as this * resolver is concerned. Fall back to DLV if available. */ if (have_ds && val->frdataset.trust >= dns_trust_secure && @@ -3588,7 +3633,8 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) if ((val->view->dlv == NULL || DLVTRIED(val)) && val->mustbesecure) { validator_log(val, ISC_LOG_WARNING, - "must be secure failure at '%s'", + "must be secure failure at '%s', " + "can't fall back to DLV", namebuf); result = DNS_R_MUSTBESECURE; goto out; @@ -3630,7 +3676,7 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) { /* * There is no DS. If this is a delegation, - * we maybe done. + * we may be done. */ /* * If we have "trust == answer" then this namespace @@ -3643,7 +3689,7 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) &val->frdataset, NULL, dsvalidated, "proveunsecure"); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) goto out; return (DNS_R_WAIT); } @@ -3655,12 +3701,13 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) if (result == DNS_R_NXRRSET && !dns_rdataset_isassociated(&val->frdataset) && dns_view_findzonecut2(val->view, tname, found, - 0, 0, ISC_FALSE, ISC_FALSE, - NULL, NULL) == ISC_R_SUCCESS && + 0, 0, ISC_FALSE, ISC_FALSE, + NULL, NULL) == ISC_R_SUCCESS && dns_name_equal(tname, found)) { if (val->mustbesecure) { validator_log(val, ISC_LOG_WARNING, - "must be secure failure"); + "must be secure failure, " + "no DS at zone cut"); return (DNS_R_MUSTBESECURE); } if (val->view->dlv == NULL || DLVTRIED(val)) { @@ -3676,13 +3723,18 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) * there's no way of validating existing * negative response blobs, give up. */ + validator_log(val, ISC_LOG_WARNING, + "can't validate existing " + "negative responses (no DS)"); result = DNS_R_NOVALIDSIG; goto out; } if (isdelegation(tname, &val->frdataset, result)) { if (val->mustbesecure) { validator_log(val, ISC_LOG_WARNING, - "must be secure failure"); + "must be secure failure, " + "%s is a delegation", + namebuf); return (DNS_R_MUSTBESECURE); } if (val->view->dlv == NULL || DLVTRIED(val)) { @@ -3705,7 +3757,10 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) if (val->mustbesecure) { validator_log(val, ISC_LOG_WARNING, - "must be secure failure"); + "must be secure failure, " + "no supported algorithm/" + "digest (%s/DS)", + namebuf); result = DNS_R_MUSTBESECURE; goto out; } @@ -3723,6 +3778,8 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) } else if (!dns_rdataset_isassociated(&val->fsigrdataset)) { + validator_log(val, ISC_LOG_DEBUG(3), + "DS is unsigned"); result = DNS_R_NOVALIDSIG; goto out; } @@ -3771,6 +3828,10 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) * there's no way of validating existing * negative response blobs, give up. */ + validator_log(val, ISC_LOG_WARNING, + "can't validate existing " + "negative responses " + "(not a zone cut)"); result = DNS_R_NOVALIDSIG; goto out; } @@ -3790,7 +3851,7 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) /* Couldn't complete insecurity proof */ validator_log(val, ISC_LOG_DEBUG(3), "insecurity proof failed"); - return (DNS_R_NOTINSECURE); /* Couldn't complete insecurity proof */ + return (DNS_R_NOTINSECURE); out: if (dns_rdataset_isassociated(&val->frdataset)) @@ -3829,7 +3890,7 @@ dlv_validator_start(dns_validator_t *val) { * \li 3. a negative answer (secure or unsecure). * * Note a answer that appears to be a secure positive answer may actually - * be a unsecure positive answer. + * be an unsecure positive answer. */ static void validator_start(isc_task_t *task, isc_event_t *event) { @@ -3895,6 +3956,10 @@ validator_start(isc_task_t *task, isc_event_t *event) { val->attributes |= VALATTR_INSECURITY; result = proveunsecure(val, ISC_FALSE, ISC_FALSE); + if (result == DNS_R_NOTINSECURE) + validator_log(val, ISC_LOG_INFO, + "got insecure response; " + "parent indicates it should be secure"); } else if (val->event->rdataset == NULL && val->event->sigrdataset == NULL) { @@ -3967,6 +4032,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, return (ISC_R_NOMEMORY); val->view = NULL; dns_view_weakattach(view, &val->view); + event = (dns_validatorevent_t *) isc_event_allocate(view->mctx, task, DNS_EVENT_VALIDATORSTART, @@ -3995,8 +4061,12 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, val->fetch = NULL; val->subvalidator = NULL; val->parent = NULL; + val->keytable = NULL; - dns_keytable_attach(val->view->secroots, &val->keytable); + result = dns_view_getsecroots(val->view, &val->keytable); + if (result != ISC_R_SUCCESS) + return (result); + val->keynode = NULL; val->key = NULL; val->siginfo = NULL; diff --git a/lib/dns/view.c b/lib/dns/view.c index 809cc15..24f925a 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,13 +15,16 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.c,v 1.150.84.6 2010-09-24 08:09:08 marka Exp $ */ +/* $Id: view.c,v 1.178 2011-01-13 09:53:04 marka Exp $ */ /*! \file */ #include +#include #include +#include +#include #include #include /* Required for HP/UX (and others?) */ #include @@ -33,17 +36,24 @@ #include #include #include +#ifdef BIND9 +#include +#endif +#include #include #include #include +#include #include #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -85,6 +95,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, if (result != ISC_R_SUCCESS) goto cleanup_name; +#ifdef BIND9 view->zonetable = NULL; result = dns_zt_create(mctx, rdclass, &view->zonetable); if (result != ISC_R_SUCCESS) { @@ -94,24 +105,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, result = ISC_R_UNEXPECTED; goto cleanup_mutex; } - view->secroots = NULL; - result = dns_keytable_create(mctx, &view->secroots); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "dns_keytable_create() failed: %s", - isc_result_totext(result)); - result = ISC_R_UNEXPECTED; - goto cleanup_zt; - } - view->trustedkeys = NULL; - result = dns_keytable_create(mctx, &view->trustedkeys); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "dns_keytable_create() failed: %s", - isc_result_totext(result)); - result = ISC_R_UNEXPECTED; - goto cleanup_secroots; - } +#endif + view->secroots_priv = NULL; view->fwdtable = NULL; result = dns_fwdtable_create(mctx, &view->fwdtable); if (result != ISC_R_SUCCESS) { @@ -119,7 +114,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, "dns_fwdtable_create() failed: %s", isc_result_totext(result)); result = ISC_R_UNEXPECTED; - goto cleanup_trustedkeys; + goto cleanup_zt; } view->acache = NULL; @@ -155,6 +150,9 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->rootexclude = NULL; view->resstats = NULL; view->resquerystats = NULL; + view->cacheshared = ISC_FALSE; + ISC_LIST_INIT(view->dns64); + view->dns64cnt = 0; /* * Initialize configuration data with default values. @@ -179,6 +177,10 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->notifyacl = NULL; view->updateacl = NULL; view->upfwdacl = NULL; + view->denyansweracl = NULL; + view->answeracl_exclude = NULL; + view->denyanswernames = NULL; + view->answernames_exclude = NULL; view->requestixfr = ISC_TRUE; view->provideixfr = ISC_TRUE; view->maxcachettl = 7 * 24 * 3600; @@ -188,11 +190,20 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->flush = ISC_FALSE; view->dlv = NULL; view->maxudp = 0; + view->v4_aaaa = dns_v4_aaaa_ok; + view->v4_aaaa_acl = NULL; + ISC_LIST_INIT(view->rpz_zones); dns_fixedname_init(&view->dlv_fixed); + view->managed_keys = NULL; +#ifdef BIND9 + view->new_zone_file = NULL; + view->new_zone_config = NULL; + view->cfg_destroy = NULL; result = dns_order_create(view->mctx, &view->order); if (result != ISC_R_SUCCESS) goto cleanup_dynkeys; +#endif result = dns_peerlist_new(view->mctx, &view->peers); if (result != ISC_R_SUCCESS) @@ -222,10 +233,12 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_peerlist_detach(&view->peers); cleanup_order: +#ifdef BIND9 dns_order_detach(&view->order); cleanup_dynkeys: - dns_tsigkeyring_destroy(&view->dynamickeys); +#endif + dns_tsigkeyring_detach(&view->dynamickeys); cleanup_references: isc_refcount_destroy(&view->references); @@ -233,16 +246,12 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, cleanup_fwdtable: dns_fwdtable_destroy(&view->fwdtable); - cleanup_trustedkeys: - dns_keytable_detach(&view->trustedkeys); - - cleanup_secroots: - dns_keytable_detach(&view->secroots); - cleanup_zt: +#ifdef BIND9 dns_zt_detach(&view->zonetable); cleanup_mutex: +#endif DESTROYLOCK(&view->lock); cleanup_name: @@ -256,6 +265,10 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, static inline void destroy(dns_view_t *view) { +#ifdef BIND9 + dns_dns64_t *dns64; +#endif + REQUIRE(!ISC_LINK_LINKED(view, link)); REQUIRE(isc_refcount_current(&view->references) == 0); REQUIRE(view->weakrefs == 0); @@ -263,23 +276,62 @@ destroy(dns_view_t *view) { REQUIRE(ADBSHUTDOWN(view)); REQUIRE(REQSHUTDOWN(view)); +#ifdef BIND9 if (view->order != NULL) dns_order_detach(&view->order); +#endif if (view->peers != NULL) dns_peerlist_detach(&view->peers); - if (view->dynamickeys != NULL) - dns_tsigkeyring_destroy(&view->dynamickeys); + + if (view->dynamickeys != NULL) { + isc_result_t result; + char template[20]; + char keyfile[20]; + FILE *fp = NULL; + int n; + + n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys", + view->name); + if (n > 0 && (size_t)n < sizeof(keyfile)) { + result = isc_file_mktemplate(keyfile, template, + sizeof(template)); + if (result == ISC_R_SUCCESS) + (void)isc_file_openuniqueprivate(template, &fp); + } + if (fp == NULL) + dns_tsigkeyring_detach(&view->dynamickeys); + else { + result = dns_tsigkeyring_dumpanddetach( + &view->dynamickeys, fp); + if (result == ISC_R_SUCCESS) { + if (fclose(fp) == 0) + result = isc_file_rename(template, + keyfile); + if (result != ISC_R_SUCCESS) + (void)remove(template); + } else { + (void)fclose(fp); + (void)remove(template); + } + } + } if (view->statickeys != NULL) - dns_tsigkeyring_destroy(&view->statickeys); + dns_tsigkeyring_detach(&view->statickeys); if (view->adb != NULL) dns_adb_detach(&view->adb); if (view->resolver != NULL) dns_resolver_detach(&view->resolver); +#ifdef BIND9 if (view->acache != NULL) { if (view->cachedb != NULL) dns_acache_putdb(view->acache, view->cachedb); dns_acache_detach(&view->acache); } + dns_rpz_view_destroy(view); +#else + INSIST(view->acache == NULL); + INSIST(ISC_LIST_EMPTY(view->rpz_zones)); +#endif if (view->requestmgr != NULL) dns_requestmgr_detach(&view->requestmgr); if (view->task != NULL) @@ -318,6 +370,16 @@ destroy(dns_view_t *view) { dns_acl_detach(&view->updateacl); if (view->upfwdacl != NULL) dns_acl_detach(&view->upfwdacl); + if (view->denyansweracl != NULL) + dns_acl_detach(&view->denyansweracl); + if (view->v4_aaaa_acl != NULL) + dns_acl_detach(&view->v4_aaaa_acl); + if (view->answeracl_exclude != NULL) + dns_rbt_destroy(&view->answeracl_exclude); + if (view->denyanswernames != NULL) + dns_rbt_destroy(&view->denyanswernames); + if (view->answernames_exclude != NULL) + dns_rbt_destroy(&view->answernames_exclude); if (view->delonly != NULL) { dns_name_t *name; int i; @@ -357,8 +419,19 @@ destroy(dns_view_t *view) { isc_stats_detach(&view->resstats); if (view->resquerystats != NULL) dns_stats_detach(&view->resquerystats); - dns_keytable_detach(&view->trustedkeys); - dns_keytable_detach(&view->secroots); + if (view->secroots_priv != NULL) + dns_keytable_detach(&view->secroots_priv); +#ifdef BIND9 + for (dns64 = ISC_LIST_HEAD(view->dns64); + dns64 != NULL; + dns64 = ISC_LIST_HEAD(view->dns64)) { + dns_dns64_unlink(&view->dns64, dns64); + dns_dns64_destroy(&dns64); + } + if (view->managed_keys != NULL) + dns_zone_detach(&view->managed_keys); + dns_view_setnewzones(view, ISC_FALSE, NULL, NULL); +#endif dns_fwdtable_destroy(&view->fwdtable); dns_aclenv_destroy(&view->aclenv); DESTROYLOCK(&view->lock); @@ -414,12 +487,19 @@ view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) { dns_adb_shutdown(view->adb); if (!REQSHUTDOWN(view)) dns_requestmgr_shutdown(view->requestmgr); +#ifdef BIND9 if (view->acache != NULL) dns_acache_shutdown(view->acache); if (view->flush) dns_zt_flushanddetach(&view->zonetable); else dns_zt_detach(&view->zonetable); + if (view->managed_keys != NULL) { + if (view->flush) + dns_zone_flush(view->managed_keys); + dns_zone_detach(&view->managed_keys); + } +#endif done = all_done(view); UNLOCK(&view->lock); } @@ -440,6 +520,7 @@ dns_view_detach(dns_view_t **viewp) { view_flushanddetach(viewp, ISC_FALSE); } +#ifdef BIND9 static isc_result_t dialup(dns_zone_t *zone, void *dummy) { UNUSED(dummy); @@ -452,6 +533,7 @@ dns_view_dialup(dns_view_t *view) { REQUIRE(DNS_VIEW_VALID(view)); (void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL); } +#endif void dns_view_weakattach(dns_view_t *source, dns_view_t **targetp) { @@ -633,12 +715,20 @@ dns_view_createresolver(dns_view_t *view, void dns_view_setcache(dns_view_t *view, dns_cache_t *cache) { + dns_view_setcache2(view, cache, ISC_FALSE); +} + +void +dns_view_setcache2(dns_view_t *view, dns_cache_t *cache, isc_boolean_t shared) { REQUIRE(DNS_VIEW_VALID(view)); REQUIRE(!view->frozen); + view->cacheshared = shared; if (view->cache != NULL) { +#ifdef BIND9 if (view->acache != NULL) dns_acache_putdb(view->acache, view->cachedb); +#endif dns_db_detach(&view->cachedb); dns_cache_detach(&view->cache); } @@ -646,8 +736,17 @@ dns_view_setcache(dns_view_t *view, dns_cache_t *cache) { dns_cache_attachdb(cache, &view->cachedb); INSIST(DNS_DB_VALID(view->cachedb)); +#ifdef BIND9 if (view->acache != NULL) dns_acache_setdb(view->acache, view->cachedb); +#endif +} + +isc_boolean_t +dns_view_iscacheshared(dns_view_t *view) { + REQUIRE(DNS_VIEW_VALID(view)); + + return (view->cacheshared); } void @@ -665,26 +764,52 @@ dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) { REQUIRE(DNS_VIEW_VALID(view)); REQUIRE(ring != NULL); if (view->statickeys != NULL) - dns_tsigkeyring_destroy(&view->statickeys); - view->statickeys = ring; + dns_tsigkeyring_detach(&view->statickeys); + dns_tsigkeyring_attach(ring, &view->statickeys); } void -dns_view_setdstport(dns_view_t *view, in_port_t dstport) { +dns_view_setdynamickeyring(dns_view_t *view, dns_tsig_keyring_t *ring) { REQUIRE(DNS_VIEW_VALID(view)); - view->dstport = dstport; + REQUIRE(ring != NULL); + if (view->dynamickeys != NULL) + dns_tsigkeyring_detach(&view->dynamickeys); + dns_tsigkeyring_attach(ring, &view->dynamickeys); } -isc_result_t -dns_view_addzone(dns_view_t *view, dns_zone_t *zone) { - isc_result_t result; +void +dns_view_getdynamickeyring(dns_view_t *view, dns_tsig_keyring_t **ringp) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(ringp != NULL && *ringp == NULL); + if (view->dynamickeys != NULL) + dns_tsigkeyring_attach(view->dynamickeys, ringp); +} + +void +dns_view_restorekeyring(dns_view_t *view) { + FILE *fp; + char keyfile[20]; + int n; REQUIRE(DNS_VIEW_VALID(view)); - REQUIRE(!view->frozen); - result = dns_zt_mount(view->zonetable, zone); + if (view->dynamickeys != NULL) { + n = snprintf(keyfile, sizeof(keyfile), "%s.tsigkeys", + view->name); + if (n > 0 && (size_t)n < sizeof(keyfile)) { + fp = fopen(keyfile, "r"); + if (fp != NULL) { + dns_keyring_restore(view->dynamickeys, fp); + (void)fclose(fp); + } + } + } +} - return (result); +void +dns_view_setdstport(dns_view_t *view, in_port_t dstport) { + REQUIRE(DNS_VIEW_VALID(view)); + view->dstport = dstport; } void @@ -699,6 +824,29 @@ dns_view_freeze(dns_view_t *view) { view->frozen = ISC_TRUE; } +#ifdef BIND9 +void +dns_view_thaw(dns_view_t *view) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(view->frozen); + + view->frozen = ISC_FALSE; +} + +isc_result_t +dns_view_addzone(dns_view_t *view, dns_zone_t *zone) { + isc_result_t result; + + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(!view->frozen); + + result = dns_zt_mount(view->zonetable, zone); + + return (result); +} +#endif + +#ifdef BIND9 isc_result_t dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) { isc_result_t result; @@ -713,20 +861,37 @@ dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) { return (result); } +#endif isc_result_t dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints, dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname, - dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) { + return (dns_view_find2(view, name, type, now, options, use_hints, + ISC_FALSE, dbp, nodep, foundname, rdataset, + sigrdataset)); +} + +isc_result_t +dns_view_find2(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, + isc_stdtime_t now, unsigned int options, + isc_boolean_t use_hints, isc_boolean_t use_static_stub, + dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) { isc_result_t result; dns_db_t *db, *zdb; dns_dbnode_t *node, *znode; - isc_boolean_t is_cache; + isc_boolean_t is_cache, is_staticstub_zone; dns_rdataset_t zrdataset, zsigrdataset; dns_zone_t *zone; +#ifndef BIND9 + UNUSED(use_hints); + UNUSED(use_static_stub); +#endif + /* * Find an rdataset whose owner name is 'name', and whose type is * 'type'. @@ -752,15 +917,30 @@ dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, zone = NULL; db = NULL; node = NULL; + is_staticstub_zone = ISC_FALSE; +#ifdef BIND9 result = dns_zt_find(view->zonetable, name, 0, NULL, &zone); + if (zone != NULL && dns_zone_gettype(zone) == dns_zone_staticstub && + !use_static_stub) { + result = ISC_R_NOTFOUND; + } if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { result = dns_zone_getdb(zone, &db); if (result != ISC_R_SUCCESS && view->cachedb != NULL) dns_db_attach(view->cachedb, &db); else if (result != ISC_R_SUCCESS) goto cleanup; + if (dns_zone_gettype(zone) == dns_zone_staticstub && + dns_name_equal(name, dns_zone_getorigin(zone))) { + is_staticstub_zone = ISC_TRUE; + } } else if (result == ISC_R_NOTFOUND && view->cachedb != NULL) dns_db_attach(view->cachedb, &db); +#else + result = ISC_R_NOTFOUND; + if (view->cachedb != NULL) + dns_db_attach(view->cachedb, &db); +#endif /* BIND9 */ else goto cleanup; @@ -773,8 +953,7 @@ dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, result = dns_db_find(db, name, NULL, type, options, now, &node, foundname, rdataset, sigrdataset); - if (result == DNS_R_DELEGATION || - result == ISC_R_NOTFOUND) { + if (result == DNS_R_DELEGATION || result == ISC_R_NOTFOUND) { if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && @@ -784,10 +963,13 @@ dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, dns_db_detachnode(db, &node); if (!is_cache) { dns_db_detach(&db); - if (view->cachedb != NULL) { + if (view->cachedb != NULL && !is_staticstub_zone) { /* * Either the answer is in the cache, or we * don't know it. + * Note that if the result comes from a + * static-stub zone we stop the search here + * (see the function description in view.h). */ is_cache = ISC_TRUE; dns_db_attach(view->cachedb, &db); @@ -817,7 +999,7 @@ dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, */ result = ISC_R_NOTFOUND; } else if (result == DNS_R_GLUE) { - if (view->cachedb != NULL) { + if (view->cachedb != NULL && !is_staticstub_zone) { /* * We found an answer, but the cache may be better. * Remember what we've got and go look in the cache. @@ -843,6 +1025,7 @@ dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, result = ISC_R_SUCCESS; } +#ifdef BIND9 if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) { if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); @@ -877,6 +1060,7 @@ dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, if (db == NULL && node != NULL) dns_db_detachnode(view->hints, &node); } +#endif /* BIND9 */ cleanup: if (dns_rdataset_isassociated(&zrdataset)) { @@ -905,8 +1089,10 @@ dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, } else INSIST(node == NULL); +#ifdef BIND9 if (zone != NULL) dns_zone_detach(&zone); +#endif return (result); } @@ -969,12 +1155,12 @@ dns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname, isc_result_t dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname, isc_stdtime_t now, unsigned int options, - isc_boolean_t use_hints, isc_boolean_t use_cache, + isc_boolean_t use_hints, isc_boolean_t use_cache, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) { isc_result_t result; dns_db_t *db; - isc_boolean_t is_cache, use_zone, try_hints; + isc_boolean_t is_cache, use_zone, try_hints, is_staticstub_zone; dns_zone_t *zone; dns_name_t *zfname; dns_rdataset_t zrdataset, zsigrdataset; @@ -986,6 +1172,7 @@ dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname, db = NULL; zone = NULL; use_zone = ISC_FALSE; + is_staticstub_zone = ISC_FALSE; try_hints = ISC_FALSE; zfname = NULL; @@ -999,9 +1186,16 @@ dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname, /* * Find the right database. */ +#ifdef BIND9 result = dns_zt_find(view->zonetable, name, 0, NULL, &zone); - if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { result = dns_zone_getdb(zone, &db); + if (dns_zone_gettype(zone) == dns_zone_staticstub) + is_staticstub_zone = ISC_TRUE; + } +#else + result = ISC_R_NOTFOUND; +#endif if (result == ISC_R_NOTFOUND) { /* * We're not directly authoritative for this query name, nor @@ -1064,7 +1258,9 @@ dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname, fname, rdataset, sigrdataset); if (result == ISC_R_SUCCESS) { if (zfname != NULL && - !dns_name_issubdomain(fname, zfname)) { + (!dns_name_issubdomain(fname, zfname) || + (dns_zone_staticstub && + dns_name_equal(fname, zfname)))) { /* * We found a zonecut in the cache, but our * zone delegation is better. @@ -1133,8 +1329,10 @@ dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname, } if (db != NULL) dns_db_detach(&db); +#ifdef BIND9 if (zone != NULL) dns_zone_detach(&zone); +#endif return (result); } @@ -1161,6 +1359,7 @@ dns_viewlist_find(dns_viewlist_t *list, const char *name, return (ISC_R_SUCCESS); } +#ifdef BIND9 isc_result_t dns_viewlist_findzone(dns_viewlist_t *list, dns_name_t *name, isc_boolean_t allclasses, dns_rdataclass_t rdclass, @@ -1225,6 +1424,7 @@ dns_view_loadnew(dns_view_t *view, isc_boolean_t stop) { return (dns_zt_loadnew(view->zonetable, stop)); } +#endif /* BIND9 */ isc_result_t dns_view_gettsig(dns_view_t *view, dns_name_t *keyname, dns_tsigkey_t **keyp) @@ -1269,6 +1469,7 @@ dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) { view->dynamickeys)); } +#ifdef BIND9 isc_result_t dns_view_dumpdbtostream(dns_view_t *view, FILE *fp) { isc_result_t result; @@ -1284,26 +1485,38 @@ dns_view_dumpdbtostream(dns_view_t *view, FILE *fp) { dns_resolver_printbadcache(view->resolver, fp); return (ISC_R_SUCCESS); } +#endif isc_result_t dns_view_flushcache(dns_view_t *view) { + return (dns_view_flushcache2(view, ISC_FALSE)); +} + +isc_result_t +dns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly) { isc_result_t result; REQUIRE(DNS_VIEW_VALID(view)); if (view->cachedb == NULL) return (ISC_R_SUCCESS); - result = dns_cache_flush(view->cache); - if (result != ISC_R_SUCCESS) - return (result); + if (!fixuponly) { + result = dns_cache_flush(view->cache); + if (result != ISC_R_SUCCESS) + return (result); + } +#ifdef BIND9 if (view->acache != NULL) dns_acache_putdb(view->acache, view->cachedb); +#endif dns_db_detach(&view->cachedb); dns_cache_attachdb(view->cache, &view->cachedb); +#ifdef BIND9 if (view->acache != NULL) dns_acache_setdb(view->acache, view->cachedb); if (view->resolver != NULL) dns_resolver_flushbadcache(view->resolver, NULL); +#endif dns_adb_flush(view->adb); return (ISC_R_SUCCESS); @@ -1437,11 +1650,13 @@ dns_view_getrootdelonly(dns_view_t *view) { return (view->rootdelonly); } +#ifdef BIND9 isc_result_t dns_view_freezezones(dns_view_t *view, isc_boolean_t value) { REQUIRE(DNS_VIEW_VALID(view)); return (dns_zt_freezezones(view->zonetable, value)); } +#endif void dns_view_setresstats(dns_view_t *view, isc_stats_t *stats) { @@ -1478,3 +1693,97 @@ dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp) { if (view->resquerystats != NULL) dns_stats_attach(view->resquerystats, statsp); } + +isc_result_t +dns_view_initsecroots(dns_view_t *view, isc_mem_t *mctx) { + REQUIRE(DNS_VIEW_VALID(view)); + if (view->secroots_priv != NULL) + dns_keytable_detach(&view->secroots_priv); + return (dns_keytable_create(mctx, &view->secroots_priv)); +} + +isc_result_t +dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(ktp != NULL && *ktp == NULL); + if (view->secroots_priv == NULL) + return (ISC_R_NOTFOUND); + dns_keytable_attach(view->secroots_priv, ktp); + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_view_issecuredomain(dns_view_t *view, dns_name_t *name, + isc_boolean_t *secure_domain) { + REQUIRE(DNS_VIEW_VALID(view)); + return (dns_keytable_issecuredomain(view->secroots_priv, name, + secure_domain)); +} + +void +dns_view_untrust(dns_view_t *view, dns_name_t *keyname, + dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx) +{ + isc_result_t result; + unsigned char data[4096]; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_buffer_t buffer; + dst_key_t *key = NULL; + dns_keytable_t *sr = NULL; + + /* + * Clear the revoke bit, if set, so that the key will match what's + * in secroots now. + */ + dnskey->flags &= ~DNS_KEYFLAG_REVOKE; + + /* Convert dnskey to DST key. */ + isc_buffer_init(&buffer, data, sizeof(data)); + dns_rdata_fromstruct(&rdata, dnskey->common.rdclass, + dns_rdatatype_dnskey, dnskey, &buffer); + result = dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &key); + if (result != ISC_R_SUCCESS) + return; + result = dns_view_getsecroots(view, &sr); + if (result == ISC_R_SUCCESS) { + dns_keytable_deletekeynode(sr, key); + dns_keytable_detach(&sr); + } + dst_key_free(&key); +} + +#define NZF ".nzf" + +void +dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx, + void (*cfg_destroy)(void **)) +{ + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE((cfgctx != NULL && cfg_destroy != NULL) || !allow); + +#ifdef BIND9 + if (view->new_zone_file != NULL) { + isc_mem_free(view->mctx, view->new_zone_file); + view->new_zone_file = NULL; + } + + if (view->new_zone_config != NULL) { + view->cfg_destroy(&view->new_zone_config); + view->cfg_destroy = NULL; + } + + if (allow) { + char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(NZF)]; + isc_sha256_data((void *)view->name, strlen(view->name), buffer); + /* Truncate the hash at 16 chars; full length is overkill */ + isc_string_printf(buffer + 16, sizeof(NZF), "%s", NZF); + view->new_zone_file = isc_mem_strdup(view->mctx, buffer); + view->new_zone_config = cfgctx; + view->cfg_destroy = cfg_destroy; + } +#else + UNUSED(allow); + UNUSED(cfgctx); + UNUSED(cfg_destroy); +#endif +} diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index b3f2e95..210bca9 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: xfrin.c,v 1.166 2008-09-25 04:12:39 marka Exp $ */ +/* $Id: xfrin.c,v 1.166.522.2.2.1 2011-06-02 23:47:35 tbox Exp $ */ /*! \file */ @@ -83,8 +83,9 @@ typedef enum { XFRST_IXFR_DEL, XFRST_IXFR_ADDSOA, XFRST_IXFR_ADD, + XFRST_IXFR_END, XFRST_AXFR, - XFRST_END + XFRST_AXFR_END } xfrin_state_t; /*% @@ -203,6 +204,7 @@ static isc_result_t axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op, dns_rdata_t *rdata); static isc_result_t axfr_apply(dns_xfrin_ctx_t *xfr); static isc_result_t axfr_commit(dns_xfrin_ctx_t *xfr); +static isc_result_t axfr_finalize(dns_xfrin_ctx_t *xfr); static isc_result_t ixfr_init(dns_xfrin_ctx_t *xfr); static isc_result_t ixfr_apply(dns_xfrin_ctx_t *xfr); @@ -318,6 +320,16 @@ axfr_commit(dns_xfrin_ctx_t *xfr) { CHECK(axfr_apply(xfr)); CHECK(dns_db_endload(xfr->db, &xfr->axfr.add_private)); + + result = ISC_R_SUCCESS; + failure: + return (result); +} + +static isc_result_t +axfr_finalize(dns_xfrin_ctx_t *xfr) { + isc_result_t result; + CHECK(dns_zone_replacedb(xfr->zone, xfr->db, ISC_TRUE)); result = ISC_R_SUCCESS; @@ -541,7 +553,7 @@ xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, isc_uint32_t ttl, isc_uint32_t soa_serial = dns_soa_getserial(rdata); if (soa_serial == xfr->end_serial) { CHECK(ixfr_commit(xfr)); - xfr->state = XFRST_END; + xfr->state = XFRST_IXFR_END; break; } else if (soa_serial != xfr->ixfr.current_serial) { xfrin_log(xfr, ISC_LOG_ERROR, @@ -572,11 +584,12 @@ xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, isc_uint32_t ttl, CHECK(axfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata)); if (rdata->type == dns_rdatatype_soa) { CHECK(axfr_commit(xfr)); - xfr->state = XFRST_END; + xfr->state = XFRST_AXFR_END; break; } break; - case XFRST_END: + case XFRST_AXFR_END: + case XFRST_IXFR_END: FAIL(DNS_R_EXTRADATA); default: INSIST(0); @@ -1318,8 +1331,9 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) { } else if (dns_message_gettsigkey(msg) != NULL) { xfr->sincetsig++; - if (xfr->sincetsig > 100 || - xfr->nmsg == 0 || xfr->state == XFRST_END) + if (xfr->sincetsig > 100 || xfr->nmsg == 0 || + xfr->state == XFRST_AXFR_END || + xfr->state == XFRST_IXFR_END) { result = DNS_R_EXPECTEDTSIG; goto failure; @@ -1345,16 +1359,22 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) { dns_message_destroy(&msg); - if (xfr->state == XFRST_GOTSOA) { + switch (xfr->state) { + case XFRST_GOTSOA: xfr->reqtype = dns_rdatatype_axfr; xfr->state = XFRST_INITIALSOA; CHECK(xfrin_send_request(xfr)); - } else if (xfr->state == XFRST_END) { + break; + case XFRST_AXFR_END: + CHECK(axfr_finalize(xfr)); + /* FALLTHROUGH */ + case XFRST_IXFR_END: /* * Close the journal. */ if (xfr->ixfr.journal != NULL) dns_journal_destroy(&xfr->ixfr.journal); + /* * Inform the caller we succeeded. */ @@ -1368,7 +1388,8 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) { */ xfr->shuttingdown = ISC_TRUE; maybe_free(xfr); - } else { + break; + default: /* * Read the next message. */ diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 108aefb..c727c2e 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.483.36.23 2010-12-14 00:48:22 marka Exp $ */ +/* $Id: zone.c,v 1.582.8.7 2011-02-18 23:23:08 each Exp $ */ /*! \file */ @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include #include #include @@ -56,6 +58,8 @@ #include #include #include +#include +#include #include #include #include @@ -66,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -129,6 +134,7 @@ typedef struct dns_signing dns_signing_t; typedef ISC_LIST(dns_signing_t) dns_signinglist_t; typedef struct dns_nsec3chain dns_nsec3chain_t; typedef ISC_LIST(dns_nsec3chain_t) dns_nsec3chainlist_t; +typedef struct dns_keyfetch dns_keyfetch_t; #define DNS_ZONE_CHECKLOCK #ifdef DNS_ZONE_CHECKLOCK @@ -200,6 +206,8 @@ struct dns_zone { isc_time_t keywarntime; isc_time_t signingtime; isc_time_t nsec3chaintime; + isc_time_t refreshkeytime; + isc_uint32_t refreshkeycount; isc_uint32_t refresh; isc_uint32_t retry; isc_uint32_t expire; @@ -273,13 +281,13 @@ struct dns_zone { /*% * Statistics counters about zone management. */ - isc_stats_t *stats; + isc_stats_t *stats; /*% * Optional per-zone statistics counters. Counted outside of this * module. */ - isc_boolean_t requeststats_on; - isc_stats_t *requeststats; + isc_boolean_t requeststats_on; + isc_stats_t *requeststats; isc_uint32_t notifydelay; dns_isselffunc_t isself; void *isselfarg; @@ -304,6 +312,21 @@ struct dns_zone { isc_uint32_t signatures; isc_uint32_t nodes; dns_rdatatype_t privatetype; + + /*% + * Autosigning/key-maintenance options + */ + isc_uint32_t keyopts; + + /*% + * True if added by "rndc addzone" + */ + isc_boolean_t added; + + /*% + * whether a rpz radix was needed when last loaded + */ + isc_boolean_t rpz_zone; }; #define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0)) @@ -339,7 +362,7 @@ struct dns_zone { * from SOA (if not set, we * are still using * default timer values) */ -#define DNS_ZONEFLG_FORCEXFER 0x00008000U /*%< Force a zone xfer */ +#define DNS_ZONEFLG_FORCEXFER 0x00008000U /*%< Force a zone xfer */ #define DNS_ZONEFLG_NOREFRESH 0x00010000U #define DNS_ZONEFLG_DIALNOTIFY 0x00020000U #define DNS_ZONEFLG_DIALREFRESH 0x00040000U @@ -352,8 +375,11 @@ struct dns_zone { #define DNS_ZONEFLG_NEEDCOMPACT 0x02000000U #define DNS_ZONEFLG_REFRESHING 0x04000000U /*%< Refreshing keydata */ #define DNS_ZONEFLG_THAW 0x08000000U +/* #define DNS_ZONEFLG_XXXXX 0x10000000U XXXMPA unused. */ +#define DNS_ZONEFLG_NODELAY 0x20000000U #define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0) +#define DNS_ZONEKEY_OPTION(z,o) (((z)->keyopts & (o)) != 0) /* Flags for zone_load() */ #define DNS_ZONELOADFLAG_NOSTAT 0x00000001U /* Do not stat() master files */ @@ -484,7 +510,7 @@ struct dns_io { * DNSKEY as result of an update. */ struct dns_signing { - unsigned int magic; + unsigned int magic; dns_db_t *db; dns_dbiterator_t *dbiterator; dns_secalg_t algorithm; @@ -495,15 +521,15 @@ struct dns_signing { }; struct dns_nsec3chain { - unsigned int magic; + unsigned int magic; dns_db_t *db; dns_dbiterator_t *dbiterator; dns_rdata_nsec3param_t nsec3param; unsigned char salt[255]; isc_boolean_t done; - isc_boolean_t seen_nsec; - isc_boolean_t delete_nsec; - isc_boolean_t save_delete_nsec; + isc_boolean_t seen_nsec; + isc_boolean_t delete_nsec; + isc_boolean_t save_delete_nsec; ISC_LINK(dns_nsec3chain_t) link; }; /*%< @@ -528,6 +554,19 @@ struct dns_nsec3chain { * so it can be recovered in the event of a error. */ +struct dns_keyfetch { + dns_fixedname_t name; + dns_rdataset_t keydataset; + dns_rdataset_t dnskeyset; + dns_rdataset_t dnskeysigset; + dns_zone_t *zone; + dns_db_t *db; + dns_fetch_t *fetch; +}; + +#define HOUR 3600 +#define DAY (24*HOUR) +#define MONTH (30*DAY) #define SEND_BUFFER_SIZE 2048 @@ -538,6 +577,10 @@ static void zone_debuglog(dns_zone_t *zone, const char *, int debuglevel, static void notify_log(dns_zone_t *zone, int level, const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4); static void queue_xfrin(dns_zone_t *zone); +static isc_result_t update_one_rr(dns_db_t *db, dns_dbversion_t *ver, + dns_diff_t *diff, dns_diffop_t op, + dns_name_t *name, dns_ttl_t ttl, + dns_rdata_t *rdata); static void zone_unload(dns_zone_t *zone); static void zone_expire(dns_zone_t *zone); static void zone_iattach(dns_zone_t *source, dns_zone_t **target); @@ -613,6 +656,10 @@ static isc_boolean_t dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_time_t *now); static isc_result_t zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid, isc_boolean_t delete); +static isc_result_t delete_nsec(dns_db_t *db, dns_dbversion_t *ver, + dns_dbnode_t *node, dns_name_t *name, + dns_diff_t *diff); +static void zone_rekey(dns_zone_t *zone); #define ENTER zone_debuglog(zone, me, 1, "enter") @@ -710,6 +757,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { zone->type = dns_zone_none; zone->flags = 0; zone->options = 0; + zone->keyopts = 0; zone->db_argc = 0; zone->db_argv = NULL; isc_time_settoepoch(&zone->expiretime); @@ -721,6 +769,8 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { isc_time_settoepoch(&zone->keywarntime); isc_time_settoepoch(&zone->signingtime); isc_time_settoepoch(&zone->nsec3chaintime); + isc_time_settoepoch(&zone->refreshkeytime); + zone->refreshkeycount = 0; zone->refresh = DNS_ZONE_DEFAULTREFRESH; zone->retry = DNS_ZONE_DEFAULTRETRY; zone->expire = 0; @@ -787,6 +837,8 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { zone->signatures = 10; zone->nodes = 100; zone->privatetype = (dns_rdatatype_t)0xffffU; + zone->added = ISC_FALSE; + zone->rpz_zone = ISC_FALSE; zone->magic = ZONE_MAGIC; @@ -1304,8 +1356,8 @@ dns_zone_getjournal(dns_zone_t *zone) { * master file (if any) is written by the server, rather than being * updated manually and read by the server. * - * This is true for slave zones, stub zones, and zones that allow - * dynamic updates either by having an update policy ("ssutable") + * This is true for slave zones, stub zones, key zones, and zones that + * allow dynamic updates either by having an update policy ("ssutable") * or an "allow-update" ACL with a value other than exactly "{ none; }". */ static isc_boolean_t @@ -1314,6 +1366,7 @@ zone_isdynamic(dns_zone_t *zone) { return (ISC_TF(zone->type == dns_zone_slave || zone->type == dns_zone_stub || + zone->type == dns_zone_key || (!zone->update_disabled && zone->ssutable != NULL) || (!zone->update_disabled && zone->update_acl != NULL && !dns_acl_isnone(zone->update_acl)))); @@ -1383,11 +1436,12 @@ zone_load(dns_zone_t *zone, unsigned int flags) { */ if (zone->masterfile != NULL) { /* - * The file is already loaded. If we are just doing a + * The file is already loaded. If we are just doing a * "rndc reconfig", we are done. */ if (!isc_time_isepoch(&zone->loadtime) && - (flags & DNS_ZONELOADFLAG_NOSTAT) != 0) { + (flags & DNS_ZONELOADFLAG_NOSTAT) != 0 && + zone->rpz_zone == dns_rpz_needed()) { result = ISC_R_SUCCESS; goto cleanup; } @@ -1396,7 +1450,8 @@ zone_load(dns_zone_t *zone, unsigned int flags) { if (result == ISC_R_SUCCESS) { if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) && !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE) && - isc_time_compare(&filetime, &zone->loadtime) <= 0) { + isc_time_compare(&filetime, &zone->loadtime) <= 0 && + zone->rpz_zone == dns_rpz_needed()) { dns_zone_log(zone, ISC_LOG_DEBUG(1), "skipping load: master file " "older than last load"); @@ -1404,6 +1459,7 @@ zone_load(dns_zone_t *zone, unsigned int flags) { goto cleanup; } loadtime = filetime; + zone->rpz_zone = dns_rpz_needed(); } } @@ -1526,6 +1582,8 @@ get_master_options(dns_zone_t *zone) { options = DNS_MASTER_ZONE; if (zone->type == dns_zone_slave) options |= DNS_MASTER_SLAVE; + if (zone->type == dns_zone_key) + options |= DNS_MASTER_KEY; if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS)) options |= DNS_MASTER_CHECKNS; if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS)) @@ -1541,7 +1599,8 @@ get_master_options(dns_zone_t *zone) { if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD)) options |= DNS_MASTER_CHECKWILDCARD; if (zone->type == dns_zone_master && - (zone->update_acl != NULL || zone->ssutable != NULL)) + ((zone->update_acl != NULL && !dns_acl_isnone(zone->update_acl)) || + zone->ssutable != NULL)) options |= DNS_MASTER_RESIGN; return (options); } @@ -1740,11 +1799,12 @@ zone_check_mx(dns_zone_t *zone, dns_db_t *db, dns_name_t *name, dns_name_format(name, namebuf, sizeof namebuf); if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN || result == DNS_R_EMPTYNAME) { + if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL)) + level = ISC_LOG_WARNING; dns_zone_log(zone, level, "%s/MX '%s' has no address records (A or AAAA)", ownerbuf, namebuf); - /* XXX950 make fatal for 9.5.0. */ - return (ISC_TRUE); + return ((level == ISC_LOG_WARNING) ? ISC_TRUE : ISC_FALSE); } if (result == DNS_R_CNAME) { @@ -1986,6 +2046,113 @@ zone_check_glue(dns_zone_t *zone, dns_db_t *db, dns_name_t *name, } static isc_boolean_t +zone_rrset_check_dup(dns_zone_t *zone, dns_name_t *owner, + dns_rdataset_t *rdataset) +{ + dns_rdataset_t tmprdataset; + isc_result_t result; + isc_boolean_t answer = ISC_TRUE; + isc_boolean_t format = ISC_TRUE; + int level = ISC_LOG_WARNING; + char ownerbuf[DNS_NAME_FORMATSIZE]; + char typebuf[DNS_RDATATYPE_FORMATSIZE]; + unsigned int count1 = 0; + + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKDUPRRFAIL)) + level = ISC_LOG_ERROR; + + dns_rdataset_init(&tmprdataset); + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + dns_rdata_t rdata1 = DNS_RDATA_INIT; + unsigned int count2 = 0; + + count1++; + dns_rdataset_current(rdataset, &rdata1); + dns_rdataset_clone(rdataset, &tmprdataset); + for (result = dns_rdataset_first(&tmprdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&tmprdataset)) { + dns_rdata_t rdata2 = DNS_RDATA_INIT; + count2++; + if (count1 >= count2) + continue; + dns_rdataset_current(&tmprdataset, &rdata2); + if (dns_rdata_casecompare(&rdata1, &rdata2) == 0) { + if (format) { + dns_name_format(owner, ownerbuf, + sizeof ownerbuf); + dns_rdatatype_format(rdata1.type, + typebuf, + sizeof(typebuf)); + format = ISC_FALSE; + } + dns_zone_log(zone, level, "%s/%s has " + "semantically identical records", + ownerbuf, typebuf); + if (level == ISC_LOG_ERROR) + answer = ISC_FALSE; + break; + } + } + dns_rdataset_disassociate(&tmprdataset); + if (!format) + break; + } + return (answer); +} + +static isc_boolean_t +zone_check_dup(dns_zone_t *zone, dns_db_t *db) { + dns_dbiterator_t *dbiterator = NULL; + dns_dbnode_t *node = NULL; + dns_fixedname_t fixed; + dns_name_t *name; + dns_rdataset_t rdataset; + dns_rdatasetiter_t *rdsit = NULL; + isc_boolean_t ok = ISC_TRUE; + isc_result_t result; + + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + dns_rdataset_init(&rdataset); + + result = dns_db_createiterator(db, 0, &dbiterator); + if (result != ISC_R_SUCCESS) + return (ISC_TRUE); + + for (result = dns_dbiterator_first(dbiterator); + result == ISC_R_SUCCESS; + result = dns_dbiterator_next(dbiterator)) { + result = dns_dbiterator_current(dbiterator, &node, name); + if (result != ISC_R_SUCCESS) + continue; + + result = dns_db_allrdatasets(db, node, NULL, 0, &rdsit); + if (result != ISC_R_SUCCESS) + continue; + + for (result = dns_rdatasetiter_first(rdsit); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsit)) { + dns_rdatasetiter_current(rdsit, &rdataset); + if (!zone_rrset_check_dup(zone, name, &rdataset)) + ok = ISC_FALSE; + dns_rdataset_disassociate(&rdataset); + } + dns_rdatasetiter_destroy(&rdsit); + dns_db_detachnode(db, &node); + } + + if (node != NULL) + dns_db_detachnode(db, &node); + dns_dbiterator_destroy(&dbiterator); + + return (ok); +} + +static isc_boolean_t integrity_checks(dns_zone_t *zone, dns_db_t *db) { dns_dbiterator_t *dbiterator = NULL; dns_dbnode_t *node = NULL; @@ -2052,6 +2219,7 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) { result = dns_rdataset_next(&rdataset); } dns_rdataset_disassociate(&rdataset); + goto next; checkmx: result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_mx, @@ -2104,7 +2272,7 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) { /* * OpenSSL verification of RSA keys with exponent 3 is known to be - * broken prior OpenSSL 0.9.8c/0.9.7k. Look for such keys and warn + * broken prior OpenSSL 0.9.8c/0.9.7k. Look for such keys and warn * if they are in use. */ static void @@ -2168,7 +2336,6 @@ zone_check_dnskeys(dns_zone_t *zone, dns_db_t *db) { dns_db_detachnode(db, &node); if (version != NULL) dns_db_closeversion(db, &version, ISC_FALSE); - } static void @@ -2189,15 +2356,18 @@ resume_signingwithkey(dns_zone_t *zone) { zone->privatetype, dns_rdatatype_none, 0, &rdataset, NULL); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + INSIST(!dns_rdataset_isassociated(&rdataset)); goto cleanup; + } for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(&rdataset)) { dns_rdataset_current(&rdataset, &rdata); - if (rdata.length != 5 || rdata.data[4] != 0) { + if (rdata.length != 5 || + rdata.data[0] == 0 || rdata.data[4] != 0) { dns_rdata_reset(&rdata); continue; } @@ -2219,7 +2389,6 @@ resume_signingwithkey(dns_zone_t *zone) { dns_db_detachnode(zone->db, &node); if (version != NULL) dns_db_closeversion(zone->db, &version, ISC_FALSE); - } static isc_result_t @@ -2228,6 +2397,9 @@ zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { isc_result_t result; isc_time_t now; unsigned int options = 0; + char saltbuf[255*2+1]; + char flags[sizeof("REMOVE|CREATE|NONSEC|OPTOUT")]; + int i; nsec3chain = isc_mem_get(zone->mctx, sizeof *nsec3chain); if (nsec3chain == NULL) @@ -2249,6 +2421,40 @@ zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { nsec3chain->delete_nsec = ISC_FALSE; nsec3chain->save_delete_nsec = ISC_FALSE; + if (nsec3param->flags == 0) + strlcpy(flags, "NONE", sizeof(flags)); + else { + flags[0] = '\0'; + if (nsec3param->flags & DNS_NSEC3FLAG_REMOVE) + strlcat(flags, "REMOVE", sizeof(flags)); + if (nsec3param->flags & DNS_NSEC3FLAG_CREATE) { + if (flags[0] == '\0') + strlcpy(flags, "CREATE", sizeof(flags)); + else + strlcat(flags, "|CREATE", sizeof(flags)); + } + if (nsec3param->flags & DNS_NSEC3FLAG_NONSEC) { + if (flags[0] == '\0') + strlcpy(flags, "NONSEC", sizeof(flags)); + else + strlcat(flags, "|NONSEC", sizeof(flags)); + } + if (nsec3param->flags & DNS_NSEC3FLAG_OPTOUT) { + if (flags[0] == '\0') + strlcpy(flags, "OPTOUT", sizeof(flags)); + else + strlcat(flags, "|OPTOUT", sizeof(flags)); + } + } + if (nsec3param->salt_length == 0) + strlcpy(saltbuf, "-", sizeof(saltbuf)); + else + for (i = 0; i < nsec3param->salt_length; i++) + sprintf(&saltbuf[i*2], "%02X", nsec3chain->salt[i]); + dns_zone_log(zone, ISC_LOG_INFO, + "zone_addnsec3chain(%u,%s,%u,%s)", + nsec3param->hash, flags, nsec3param->iterations, + saltbuf); for (current = ISC_LIST_HEAD(zone->nsec3chain); current != NULL; current = ISC_LIST_NEXT(current, link)) { @@ -2298,11 +2504,13 @@ static void resume_addnsec3chain(dns_zone_t *zone) { dns_dbnode_t *node = NULL; dns_dbversion_t *version = NULL; - dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_t rdataset; isc_result_t result; dns_rdata_nsec3param_t nsec3param; + if (zone->privatetype == 0) + return; + result = dns_db_findnode(zone->db, &zone->origin, ISC_FALSE, &node); if (result != ISC_R_SUCCESS) goto cleanup; @@ -2310,17 +2518,25 @@ resume_addnsec3chain(dns_zone_t *zone) { dns_db_currentversion(zone->db, &version); dns_rdataset_init(&rdataset); result = dns_db_findrdataset(zone->db, node, version, - dns_rdatatype_nsec3param, - dns_rdatatype_none, 0, - &rdataset, NULL); - if (result != ISC_R_SUCCESS) + zone->privatetype, dns_rdatatype_none, + 0, &rdataset, NULL); + if (result != ISC_R_SUCCESS) { + INSIST(!dns_rdataset_isassociated(&rdataset)); goto cleanup; + } for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(&rdataset)) { - dns_rdataset_current(&rdataset, &rdata); + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_t private = DNS_RDATA_INIT; + + dns_rdataset_current(&rdataset, &private); + if (!dns_nsec3param_fromprivate(&private, &rdata, buf, + sizeof(buf))) + continue; result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); if ((nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0 || @@ -2332,10 +2548,8 @@ resume_addnsec3chain(dns_zone_t *zone) { dns_result_totext(result)); } } - dns_rdata_reset(&rdata); } dns_rdataset_disassociate(&rdataset); - cleanup: if (node != NULL) dns_db_detachnode(zone->db, &node); @@ -2353,8 +2567,8 @@ set_resigntime(dns_zone_t *zone) { dns_rdataset_init(&rdataset); dns_fixedname_init(&fixed); - result = dns_db_getsigningtime(zone->db, &rdataset, - dns_fixedname_name(&fixed)); + result = dns_db_getsigningtime(zone->db, &rdataset, + dns_fixedname_name(&fixed)); if (result != ISC_R_SUCCESS) { isc_time_settoepoch(&zone->resigntime); return; @@ -2392,10 +2606,12 @@ check_nsec3param(dns_zone_t *zone, dns_db_t *db) { dns_rdatatype_nsec3param, dns_rdatatype_none, 0, &rdataset, NULL); if (result == ISC_R_NOTFOUND) { + INSIST(!dns_rdataset_isassociated(&rdataset)); result = ISC_R_SUCCESS; goto cleanup; } if (result != ISC_R_SUCCESS) { + INSIST(!dns_rdataset_isassociated(&rdataset)); dns_zone_log(zone, ISC_LOG_ERROR, "nsec3param lookup failure: %s", dns_result_totext(result)); @@ -2456,1230 +2672,1837 @@ check_nsec3param(dns_zone_t *zone, dns_db_t *db) { return (result); } +/* + * Set the timer for refreshing the key zone to the soonest future time + * of the set (current timer, keydata->refresh, keydata->addhd, + * keydata->removehd). + */ +static void +set_refreshkeytimer(dns_zone_t *zone, dns_rdata_keydata_t *key, + isc_stdtime_t now) { + const char me[] = "set_refreshkeytimer"; + isc_stdtime_t then; + isc_time_t timenow, timethen; + char timebuf[80]; + + ENTER; + then = key->refresh; + if (key->addhd > now && key->addhd < then) + then = key->addhd; + if (key->removehd > now && key->removehd < then) + then = key->removehd; + + TIME_NOW(&timenow); + if (then > now) + DNS_ZONE_TIME_ADD(&timenow, then - now, &timethen); + else + timethen = timenow; + if (isc_time_compare(&zone->refreshkeytime, &timenow) < 0 || + isc_time_compare(&timethen, &zone->refreshkeytime) < 0) + zone->refreshkeytime = timethen; + + isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80); + dns_zone_log(zone, ISC_LOG_DEBUG(1), "next key refresh: %s", timebuf); + zone_settimer(zone, &timenow); +} + +/* + * Convert key(s) linked from 'keynode' to KEYDATA and add to the key zone. + * If the key zone is changed, set '*changed' to ISC_TRUE. + */ static isc_result_t -zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, - isc_result_t result) +create_keydata(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, + dns_diff_t *diff, dns_keytable_t *keytable, + dns_keynode_t **keynodep, isc_boolean_t *changed) { - unsigned int soacount = 0; - unsigned int nscount = 0; - unsigned int errors = 0; - isc_uint32_t serial, oldserial, refresh, retry, expire, minimum; - isc_time_t now; - isc_boolean_t needdump = ISC_FALSE; - isc_boolean_t hasinclude = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE); - unsigned int options; + const char me[] = "create_keydata"; + isc_result_t result = ISC_R_SUCCESS; + isc_buffer_t keyb, dstb; + unsigned char key_buf[4096], dst_buf[DST_KEY_MAXSIZE]; + dns_rdata_keydata_t keydata; + dns_rdata_dnskey_t dnskey; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_keynode_t *keynode; + isc_stdtime_t now; + isc_region_t r; + dst_key_t *key; - TIME_NOW(&now); + REQUIRE(keynodep != NULL); + keynode = *keynodep; - /* - * Initiate zone transfer? We may need a error code that - * indicates that the "permanent" form does not exist. - * XXX better error feedback to log. - */ - if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) { - if (zone->type == dns_zone_slave || - zone->type == dns_zone_stub) { - if (result == ISC_R_FILENOTFOUND) - dns_zone_log(zone, ISC_LOG_DEBUG(1), - "no master file"); - else if (result != DNS_R_NOMASTERFILE) - dns_zone_log(zone, ISC_LOG_ERROR, - "loading from master file %s " - "failed: %s", - zone->masterfile, - dns_result_totext(result)); - } else - dns_zone_log(zone, ISC_LOG_ERROR, - "loading from master file %s failed: %s", - zone->masterfile, - dns_result_totext(result)); - goto cleanup; - } + ENTER; + isc_stdtime_get(&now); - dns_zone_log(zone, ISC_LOG_DEBUG(2), - "number of nodes in database: %u", - dns_db_nodecount(db)); + /* Loop in case there's more than one key. */ + while (result == ISC_R_SUCCESS) { + dns_keynode_t *nextnode = NULL; - if (result == DNS_R_SEENINCLUDE) - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HASINCLUDE); - else - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HASINCLUDE); + key = dns_keynode_key(keynode); + if (key == NULL) + goto skip; - /* - * Apply update log, if any, on initial load. - */ - if (zone->journal != NULL && - ! DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOMERGE) && - ! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) - { - if (zone->type == dns_zone_master && - (zone->update_acl != NULL || zone->ssutable != NULL)) - options = DNS_JOURNALOPT_RESIGN; - else - options = 0; - result = dns_journal_rollforward2(zone->mctx, db, options, - zone->sigresigninginterval, - zone->journal); - if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND && - result != DNS_R_UPTODATE && result != DNS_R_NOJOURNAL && - result != ISC_R_RANGE) { - dns_zone_log(zone, ISC_LOG_ERROR, - "journal rollforward failed: %s", - dns_result_totext(result)); - goto cleanup; - } - if (result == ISC_R_NOTFOUND || result == ISC_R_RANGE) { - dns_zone_log(zone, ISC_LOG_ERROR, - "journal rollforward failed: " - "journal out of sync with zone"); - goto cleanup; + isc_buffer_init(&dstb, dst_buf, sizeof(dst_buf)); + CHECK(dst_key_todns(key, &dstb)); + + /* Convert DST key to DNSKEY. */ + dns_rdata_reset(&rdata); + isc_buffer_usedregion(&dstb, &r); + dns_rdata_fromregion(&rdata, dst_key_class(key), + dns_rdatatype_dnskey, &r); + + /* DSTKEY to KEYDATA. */ + CHECK(dns_rdata_tostruct(&rdata, &dnskey, NULL)); + CHECK(dns_keydata_fromdnskey(&keydata, &dnskey, now, 0, 0, + NULL)); + + /* KEYDATA to rdata. */ + dns_rdata_reset(&rdata); + isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); + CHECK(dns_rdata_fromstruct(&rdata, + zone->rdclass, dns_rdatatype_keydata, + &keydata, &keyb)); + + /* Add rdata to zone. */ + CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, + dst_key_name(key), 0, &rdata)); + *changed = ISC_TRUE; + + skip: + result = dns_keytable_nextkeynode(keytable, keynode, &nextnode); + if (result != ISC_R_NOTFOUND) { + dns_keytable_detachkeynode(keytable, &keynode); + keynode = nextnode; } - dns_zone_log(zone, ISC_LOG_DEBUG(1), - "journal rollforward completed " - "successfully: %s", - dns_result_totext(result)); - if (result == ISC_R_SUCCESS) - needdump = ISC_TRUE; } - zone->loadtime = loadtime; + /* Refresh new keys from the zone apex as soon as possible. */ + if (*changed) + set_refreshkeytimer(zone, &keydata, now); - dns_zone_log(zone, ISC_LOG_DEBUG(1), "loaded"); - /* - * Obtain ns, soa and cname counts for top of zone. - */ - INSIST(db != NULL); - result = zone_get_from_db(zone, db, &nscount, &soacount, &serial, - &refresh, &retry, &expire, &minimum, - &errors); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "could not find NS and/or SOA records"); + if (keynode != NULL) + dns_keytable_detachkeynode(keytable, &keynode); + *keynodep = NULL; + + return (ISC_R_SUCCESS); + + failure: + return (result); +} + +/* + * Remove from the key zone all the KEYDATA records found in rdataset. + */ +static isc_result_t +delete_keydata(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, + dns_name_t *name, dns_rdataset_t *rdataset) +{ + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_result_t result, uresult; + + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); + uresult = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, + name, 0, &rdata); + if (uresult != ISC_R_SUCCESS) + return (uresult); } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + return (result); +} - /* - * Master / Slave / Stub zones require both NS and SOA records at - * the top of the zone. - */ +/* + * Compute the DNSSEC key ID for a DNSKEY record. + */ +static isc_result_t +compute_tag(dns_name_t *name, dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx, + dns_keytag_t *tag) +{ + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned char data[4096]; + isc_buffer_t buffer; + dst_key_t *dstkey = NULL; - switch (zone->type) { - case dns_zone_master: - case dns_zone_slave: - case dns_zone_stub: - if (soacount != 1) { - dns_zone_log(zone, ISC_LOG_ERROR, - "has %d SOA records", soacount); - result = DNS_R_BADZONE; - } - if (nscount == 0) { - dns_zone_log(zone, ISC_LOG_ERROR, - "has no NS records"); - result = DNS_R_BADZONE; - } - if (result != ISC_R_SUCCESS) - goto cleanup; - if (zone->type == dns_zone_master && errors != 0) { - result = DNS_R_BADZONE; - goto cleanup; - } - if (zone->type != dns_zone_stub) { - result = check_nsec3param(zone, db); - if (result != ISC_R_SUCCESS) - goto cleanup; - } - if (zone->type == dns_zone_master && - DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKINTEGRITY) && - !integrity_checks(zone, db)) { - result = DNS_R_BADZONE; - goto cleanup; - } - - if (zone->db != NULL) { - /* - * This is checked in zone_replacedb() for slave zones - * as they don't reload from disk. - */ - result = zone_get_from_db(zone, zone->db, NULL, NULL, - &oldserial, NULL, NULL, NULL, - NULL, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) && - !isc_serial_gt(serial, oldserial)) { - isc_uint32_t serialmin, serialmax; + isc_buffer_init(&buffer, data, sizeof(data)); + dns_rdata_fromstruct(&rdata, dnskey->common.rdclass, + dns_rdatatype_dnskey, dnskey, &buffer); - INSIST(zone->type == dns_zone_master); + result = dns_dnssec_keyfromrdata(name, &rdata, mctx, &dstkey); + if (result == ISC_R_SUCCESS) + *tag = dst_key_id(dstkey); + dst_key_free(&dstkey); - serialmin = (oldserial + 1) & 0xffffffffU; - serialmax = (oldserial + 0x7fffffffU) & - 0xffffffffU; - dns_zone_log(zone, ISC_LOG_ERROR, - "ixfr-from-differences: " - "new serial (%u) out of range " - "[%u - %u]", serial, serialmin, - serialmax); - result = DNS_R_BADZONE; - goto cleanup; - } else if (!isc_serial_ge(serial, oldserial)) - dns_zone_log(zone, ISC_LOG_ERROR, - "zone serial has gone backwards"); - else if (serial == oldserial && !hasinclude) - dns_zone_log(zone, ISC_LOG_ERROR, - "zone serial unchanged. " - "zone may fail to transfer " - "to slaves."); - } + return (result); +} - if (zone->type == dns_zone_master && - (zone->update_acl != NULL || zone->ssutable != NULL) && - zone->sigresigninginterval < (3 * refresh) && - dns_db_issecure(db)) - { - dns_zone_log(zone, ISC_LOG_WARNING, - "sig-re-signing-interval less than " - "3 * refresh."); - } +/* + * Add key to the security roots for all views. + */ +static void +trust_key(dns_viewlist_t *viewlist, dns_name_t *keyname, + dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx) { + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned char data[4096]; + isc_buffer_t buffer; + dns_view_t *view; + dns_keytable_t *sr = NULL; + dst_key_t *dstkey = NULL; - zone->refresh = RANGE(refresh, - zone->minrefresh, zone->maxrefresh); - zone->retry = RANGE(retry, - zone->minretry, zone->maxretry); - zone->expire = RANGE(expire, zone->refresh + zone->retry, - DNS_MAX_EXPIRE); - zone->minimum = minimum; - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS); + /* Convert dnskey to DST key. */ + isc_buffer_init(&buffer, data, sizeof(data)); + dns_rdata_fromstruct(&rdata, dnskey->common.rdclass, + dns_rdatatype_dnskey, dnskey, &buffer); - if (zone->type == dns_zone_slave || - zone->type == dns_zone_stub) { - isc_time_t t; - isc_uint32_t delay; + for (view = ISC_LIST_HEAD(*viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) { - result = isc_file_getmodtime(zone->journal, &t); - if (result != ISC_R_SUCCESS) - result = isc_file_getmodtime(zone->masterfile, - &t); - if (result == ISC_R_SUCCESS) - DNS_ZONE_TIME_ADD(&t, zone->expire, - &zone->expiretime); - else - DNS_ZONE_TIME_ADD(&now, zone->retry, - &zone->expiretime); + result = dns_view_getsecroots(view, &sr); + if (result != ISC_R_SUCCESS) + continue; - delay = isc_random_jitter(zone->retry, - (zone->retry * 3) / 4); - DNS_ZONE_TIME_ADD(&now, delay, &zone->refreshtime); - if (isc_time_compare(&zone->refreshtime, - &zone->expiretime) >= 0) - zone->refreshtime = now; - } - break; - default: - UNEXPECTED_ERROR(__FILE__, __LINE__, - "unexpected zone type %d", zone->type); - result = ISC_R_UNEXPECTED; - goto cleanup; + CHECK(dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &dstkey)); + CHECK(dns_keytable_add(sr, ISC_TRUE, &dstkey)); + dns_keytable_detach(&sr); } - /* - * Check for weak DNSKEY's. - */ - if (zone->type == dns_zone_master) - zone_check_dnskeys(zone, db); + failure: + if (dstkey != NULL) + dst_key_free(&dstkey); + if (sr != NULL) + dns_keytable_detach(&sr); + return; +} -#if 0 - /* destroy notification example. */ - { - isc_event_t *e = isc_event_allocate(zone->mctx, NULL, - DNS_EVENT_DBDESTROYED, - dns_zonemgr_dbdestroyed, - zone, - sizeof(isc_event_t)); - dns_db_ondestroy(db, zone->task, &e); - } -#endif +/* + * Remove key from the security roots for all views. + */ +static void +untrust_key(dns_viewlist_t *viewlist, dns_name_t *keyname, isc_mem_t *mctx, + dns_rdata_dnskey_t *dnskey) +{ + dns_view_t *view; - ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); - if (zone->db != NULL) { - result = zone_replacedb(zone, db, ISC_FALSE); - ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); - if (result != ISC_R_SUCCESS) - goto cleanup; - } else { - zone_attachdb(zone, db); - ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); - DNS_ZONE_SETFLAG(zone, - DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY); - } - result = ISC_R_SUCCESS; - if (needdump) - zone_needdump(zone, DNS_DUMP_DELAY); - if (zone->task != NULL) { - if (zone->type == dns_zone_master) { - set_resigntime(zone); - resume_signingwithkey(zone); - resume_addnsec3chain(zone); - } - zone_settimer(zone, &now); - } + for (view = ISC_LIST_HEAD(*viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + dns_view_untrust(view, keyname, dnskey, mctx); +} - if (! dns_db_ispersistent(db)) - dns_zone_log(zone, ISC_LOG_INFO, "loaded serial %u%s", serial, - dns_db_issecure(db) ? " (signed)" : ""); +/* + * Add a null key to the security roots for all views, so that all queries + * to the zone will fail. + */ +static void +fail_secure(dns_viewlist_t *viewlist, dns_name_t *keyname) { + isc_result_t result; + dns_view_t *view; - return (result); + for (view = ISC_LIST_HEAD(*viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + dns_keytable_t *sr = NULL; - cleanup: - if (zone->type == dns_zone_slave || - zone->type == dns_zone_stub) { - if (zone->journal != NULL) - zone_saveunique(zone, zone->journal, "jn-XXXXXXXX"); - if (zone->masterfile != NULL) - zone_saveunique(zone, zone->masterfile, "db-XXXXXXXX"); + result = dns_view_getsecroots(view, &sr); + if (result != ISC_R_SUCCESS) + continue; - /* Mark the zone for immediate refresh. */ - zone->refreshtime = now; - if (zone->task != NULL) - zone_settimer(zone, &now); - result = ISC_R_SUCCESS; - } else if (zone->type == dns_zone_master) - dns_zone_log(zone, ISC_LOG_ERROR, "not loaded due to errors."); - return (result); + dns_keytable_marksecure(sr, keyname); + dns_keytable_detach(&sr); + } } -static isc_boolean_t -exit_check(dns_zone_t *zone) { +/* + * Scan a set of KEYDATA records from the key zone. The ones that are + * valid (i.e., the add holddown timer has expired) become trusted keys for + * all views. + */ +static void +load_secroots(dns_zone_t *zone, dns_name_t *name, dns_rdataset_t *rdataset) { + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_keydata_t keydata; + dns_rdata_dnskey_t dnskey; + isc_mem_t *mctx = zone->mctx; + dns_view_t *view = zone->view; + dns_viewlist_t *viewlist = view->viewlist; + int trusted = 0, revoked = 0, pending = 0; + isc_stdtime_t now; - REQUIRE(LOCKED_ZONE(zone)); + isc_stdtime_get(&now); - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SHUTDOWN) && - zone->irefs == 0) - { - /* - * DNS_ZONEFLG_SHUTDOWN can only be set if erefs == 0. - */ - INSIST(isc_refcount_current(&zone->erefs) == 0); - return (ISC_TRUE); + /* For each view, delete references to this key from secroots. */ + for (view = ISC_LIST_HEAD(*viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) { + dns_keytable_t *sr = NULL; + + result = dns_view_getsecroots(view, &sr); + if (result != ISC_R_SUCCESS) + continue; + + dns_keytable_delete(sr, name); + dns_keytable_detach(&sr); } - return (ISC_FALSE); -} -static isc_boolean_t -zone_check_ns(dns_zone_t *zone, dns_db_t *db, dns_name_t *name) { - isc_result_t result; - char namebuf[DNS_NAME_FORMATSIZE]; - char altbuf[DNS_NAME_FORMATSIZE]; - dns_fixedname_t fixed; - dns_name_t *foundname; - int level; + /* Now insert all the accepted trust anchors from this keydata set. */ + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + dns_rdata_reset(&rdata); + dns_rdataset_current(rdataset, &rdata); - if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOCHECKNS)) - return (ISC_TRUE); + /* Convert rdata to keydata. */ + dns_rdata_tostruct(&rdata, &keydata, NULL); - if (zone->type == dns_zone_master) - level = ISC_LOG_ERROR; - else - level = ISC_LOG_WARNING; + /* Set the key refresh timer. */ + set_refreshkeytimer(zone, &keydata, now); - dns_fixedname_init(&fixed); - foundname = dns_fixedname_name(&fixed); + /* If the removal timer is nonzero, this key was revoked. */ + if (keydata.removehd != 0) { + revoked++; + continue; + } - result = dns_db_find(db, name, NULL, dns_rdatatype_a, - 0, 0, NULL, foundname, NULL, NULL); - if (result == ISC_R_SUCCESS) - return (ISC_TRUE); + /* + * If the add timer is still pending, this key is not + * trusted yet. + */ + if (now < keydata.addhd) { + pending++; + continue; + } - if (result == DNS_R_NXRRSET) { - result = dns_db_find(db, name, NULL, dns_rdatatype_aaaa, - 0, 0, NULL, foundname, NULL, NULL); - if (result == ISC_R_SUCCESS) - return (ISC_TRUE); - } + /* Convert keydata to dnskey. */ + dns_keydata_todnskey(&keydata, &dnskey, NULL); - dns_name_format(name, namebuf, sizeof namebuf); - if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN || - result == DNS_R_EMPTYNAME) { - dns_zone_log(zone, level, - "NS '%s' has no address records (A or AAAA)", - namebuf); - /* XXX950 Make fatal ISC_FALSE for 9.5.0. */ - return (ISC_TRUE); + /* Add to keytables. */ + trusted++; + trust_key(viewlist, name, &dnskey, mctx); } - if (result == DNS_R_CNAME) { - dns_zone_log(zone, level, "NS '%s' is a CNAME (illegal)", - namebuf); - /* XXX950 Make fatal ISC_FALSE for 9.5.0. */ - return (ISC_TRUE); + if (trusted == 0 && pending != 0) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namebuf, sizeof namebuf); + dns_zone_log(zone, ISC_LOG_ERROR, + "No valid trust anchors for '%s'!", namebuf); + dns_zone_log(zone, ISC_LOG_ERROR, + "%d key(s) revoked, %d still pending", + revoked, pending); + dns_zone_log(zone, ISC_LOG_ERROR, + "All queries to '%s' will fail", namebuf); + fail_secure(viewlist, name); } - - if (result == DNS_R_DNAME) { - dns_name_format(foundname, altbuf, sizeof altbuf); - dns_zone_log(zone, level, - "NS '%s' is below a DNAME '%s' (illegal)", - namebuf, altbuf); - /* XXX950 Make fatal ISC_FALSE for 9.5.0. */ - return (ISC_TRUE); - } - - return (ISC_TRUE); -} +} static isc_result_t -zone_count_ns_rr(dns_zone_t *zone, dns_db_t *db, dns_dbnode_t *node, - dns_dbversion_t *version, unsigned int *nscount, - unsigned int *errors) +do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver, + dns_diff_t *diff) { + dns_diff_t temp_diff; isc_result_t result; - unsigned int count = 0; - unsigned int ecount = 0; - dns_rdataset_t rdataset; - dns_rdata_t rdata; - dns_rdata_ns_t ns; - dns_rdataset_init(&rdataset); - result = dns_db_findrdataset(db, node, version, dns_rdatatype_ns, - dns_rdatatype_none, 0, &rdataset, NULL); - if (result == ISC_R_NOTFOUND) - goto success; - if (result != ISC_R_SUCCESS) - goto invalidate_rdataset; + /* + * Create a singleton diff. + */ + dns_diff_init(diff->mctx, &temp_diff); + temp_diff.resign = diff->resign; + ISC_LIST_APPEND(temp_diff.tuples, *tuple, link); - result = dns_rdataset_first(&rdataset); - while (result == ISC_R_SUCCESS) { - if (errors != NULL && zone->rdclass == dns_rdataclass_in && - (zone->type == dns_zone_master || - zone->type == dns_zone_slave)) { - dns_rdata_init(&rdata); - dns_rdataset_current(&rdataset, &rdata); - result = dns_rdata_tostruct(&rdata, &ns, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - if (dns_name_issubdomain(&ns.name, &zone->origin) && - !zone_check_ns(zone, db, &ns.name)) - ecount++; - } - count++; - result = dns_rdataset_next(&rdataset); + /* + * Apply it to the database. + */ + result = dns_diff_apply(&temp_diff, db, ver); + ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link); + if (result != ISC_R_SUCCESS) { + dns_difftuple_free(tuple); + return (result); } - dns_rdataset_disassociate(&rdataset); - - success: - if (nscount != NULL) - *nscount = count; - if (errors != NULL) - *errors = ecount; - result = ISC_R_SUCCESS; - - invalidate_rdataset: - dns_rdataset_invalidate(&rdataset); + /* + * Merge it into the current pending journal entry. + */ + dns_diff_appendminimal(diff, tuple); - return (result); + /* + * Do not clear temp_diff. + */ + return (ISC_R_SUCCESS); } static isc_result_t -zone_load_soa_rr(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, - unsigned int *soacount, - isc_uint32_t *serial, isc_uint32_t *refresh, - isc_uint32_t *retry, isc_uint32_t *expire, - isc_uint32_t *minimum) +update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, + dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl, + dns_rdata_t *rdata) { + dns_difftuple_t *tuple = NULL; isc_result_t result; - unsigned int count; - dns_rdataset_t rdataset; - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdata_soa_t soa; - - dns_rdataset_init(&rdataset); - result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa, - dns_rdatatype_none, 0, &rdataset, NULL); - if (result == ISC_R_NOTFOUND) { - if (soacount != NULL) - *soacount = 0; - if (serial != NULL) - *serial = 0; - if (refresh != NULL) - *refresh = 0; - if (retry != NULL) - *retry = 0; - if (expire != NULL) - *expire = 0; - if (minimum != NULL) - *minimum = 0; - result = ISC_R_SUCCESS; - goto invalidate_rdataset; - } + result = dns_difftuple_create(diff->mctx, op, + name, ttl, rdata, &tuple); if (result != ISC_R_SUCCESS) - goto invalidate_rdataset; + return (result); + return (do_one_tuple(&tuple, db, ver, diff)); +} - count = 0; - result = dns_rdataset_first(&rdataset); - while (result == ISC_R_SUCCESS) { - dns_rdata_init(&rdata); - dns_rdataset_current(&rdataset, &rdata); - count++; - if (count == 1) { - result = dns_rdata_tostruct(&rdata, &soa, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - } +static isc_result_t +increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver, + dns_diff_t *diff, isc_mem_t *mctx) { + dns_difftuple_t *deltuple = NULL; + dns_difftuple_t *addtuple = NULL; + isc_uint32_t serial; + isc_result_t result; - result = dns_rdataset_next(&rdataset); - dns_rdata_reset(&rdata); - } - dns_rdataset_disassociate(&rdataset); + CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple)); + CHECK(dns_difftuple_copy(deltuple, &addtuple)); + addtuple->op = DNS_DIFFOP_ADD; - if (soacount != NULL) - *soacount = count; + serial = dns_soa_getserial(&addtuple->rdata); - if (count > 0) { - if (serial != NULL) - *serial = soa.serial; - if (refresh != NULL) - *refresh = soa.refresh; - if (retry != NULL) - *retry = soa.retry; - if (expire != NULL) - *expire = soa.expire; - if (minimum != NULL) - *minimum = soa.minimum; - } + /* RFC1982 */ + serial = (serial + 1) & 0xFFFFFFFF; + if (serial == 0) + serial = 1; + dns_soa_setserial(serial, &addtuple->rdata); + CHECK(do_one_tuple(&deltuple, db, ver, diff)); + CHECK(do_one_tuple(&addtuple, db, ver, diff)); result = ISC_R_SUCCESS; - invalidate_rdataset: - dns_rdataset_invalidate(&rdataset); + failure: + if (addtuple != NULL) + dns_difftuple_free(&addtuple); + if (deltuple != NULL) + dns_difftuple_free(&deltuple); + return (result); +} + +/* + * Write all transactions in 'diff' to the zone journal file. + */ +static isc_result_t +zone_journal(dns_zone_t *zone, dns_diff_t *diff, const char *caller) { + const char me[] = "zone_journal"; + const char *journalfile; + isc_result_t result = ISC_R_SUCCESS; + dns_journal_t *journal = NULL; + + ENTER; + journalfile = dns_zone_getjournal(zone); + if (journalfile != NULL) { + result = dns_journal_open(zone->mctx, journalfile, + ISC_TRUE, &journal); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s:dns_journal_open -> %s\n", + caller, dns_result_totext(result)); + return (result); + } + result = dns_journal_write_transaction(journal, diff); + dns_journal_destroy(&journal); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "%s:dns_journal_write_transaction -> %s\n", + caller, dns_result_totext(result)); + return (result); + } + } return (result); } /* - * zone must be locked. + * Create an SOA record for a newly-created zone */ static isc_result_t -zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount, - unsigned int *soacount, isc_uint32_t *serial, - isc_uint32_t *refresh, isc_uint32_t *retry, - isc_uint32_t *expire, isc_uint32_t *minimum, - unsigned int *errors) -{ - dns_dbversion_t *version; +add_soa(dns_zone_t *zone, dns_db_t *db) { isc_result_t result; - isc_result_t answer = ISC_R_SUCCESS; - dns_dbnode_t *node; - - REQUIRE(db != NULL); - REQUIRE(zone != NULL); + dns_rdata_t rdata = DNS_RDATA_INIT; + unsigned char buf[DNS_SOA_BUFFERSIZE]; + dns_dbversion_t *ver = NULL; + dns_diff_t diff; - version = NULL; - dns_db_currentversion(db, &version); + dns_zone_log(zone, ISC_LOG_DEBUG(1), "creating SOA"); - node = NULL; - result = dns_db_findnode(db, &zone->origin, ISC_FALSE, &node); + dns_diff_init(zone->mctx, &diff); + result = dns_db_newversion(db, &ver); if (result != ISC_R_SUCCESS) { - answer = result; - goto closeversion; + dns_zone_log(zone, ISC_LOG_ERROR, + "add_soa:dns_db_newversion -> %s\n", + dns_result_totext(result)); + goto failure; } - if (nscount != NULL || errors != NULL) { - result = zone_count_ns_rr(zone, db, node, version, - nscount, errors); - if (result != ISC_R_SUCCESS) - answer = result; + /* Build SOA record */ + result = dns_soa_buildrdata(&zone->origin, dns_rootname, zone->rdclass, + 0, 0, 0, 0, 0, buf, &rdata); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "add_soa:dns_soa_buildrdata -> %s\n", + dns_result_totext(result)); + goto failure; } - if (soacount != NULL || serial != NULL || refresh != NULL - || retry != NULL || expire != NULL || minimum != NULL) { - result = zone_load_soa_rr(db, node, version, soacount, - serial, refresh, retry, expire, - minimum); - if (result != ISC_R_SUCCESS) - answer = result; - } + result = update_one_rr(db, ver, &diff, DNS_DIFFOP_ADD, + &zone->origin, 0, &rdata); - dns_db_detachnode(db, &node); - closeversion: - dns_db_closeversion(db, &version, ISC_FALSE); +failure: + dns_diff_clear(&diff); + if (ver != NULL) + dns_db_closeversion(db, &ver, ISC_TF(result == ISC_R_SUCCESS)); - return (answer); + return (result); } -void -dns_zone_attach(dns_zone_t *source, dns_zone_t **target) { - REQUIRE(DNS_ZONE_VALID(source)); - REQUIRE(target != NULL && *target == NULL); - isc_refcount_increment(&source->erefs, NULL); - *target = source; -} +/* + * Synchronize the set of initializing keys found in managed-keys {} + * statements with the set of trust anchors found in the managed-keys.bind + * zone. If a domain is no longer named in managed-keys, delete all keys + * from that domain from the key zone. If a domain is mentioned in in + * managed-keys but there are no references to it in the key zone, load + * the key zone with the initializing key(s) for that domain. + */ +static isc_result_t +sync_keyzone(dns_zone_t *zone, dns_db_t *db) { + isc_result_t result = ISC_R_SUCCESS; + isc_boolean_t changed = ISC_FALSE; + dns_rbtnodechain_t chain; + dns_fixedname_t fn; + dns_name_t foundname, *origin; + dns_keynode_t *keynode = NULL; + dns_view_t *view = zone->view; + dns_keytable_t *sr = NULL; + dns_dbversion_t *ver = NULL; + dns_diff_t diff; + dns_rriterator_t rrit; -void -dns_zone_detach(dns_zone_t **zonep) { - dns_zone_t *zone; - unsigned int refs; - isc_boolean_t free_now = ISC_FALSE; + dns_zone_log(zone, ISC_LOG_DEBUG(1), "synchronizing trusted keys"); - REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep)); + dns_name_init(&foundname, NULL); + dns_fixedname_init(&fn); + origin = dns_fixedname_name(&fn); - zone = *zonep; + dns_diff_init(zone->mctx, &diff); - isc_refcount_decrement(&zone->erefs, &refs); + CHECK(dns_view_getsecroots(view, &sr)); - if (refs == 0) { - LOCK_ZONE(zone); - /* - * We just detached the last external reference. - */ - if (zone->task != NULL) { - /* - * This zone is being managed. Post - * its control event and let it clean - * up synchronously in the context of - * its task. - */ - isc_event_t *ev = &zone->ctlevent; - isc_task_send(zone->task, &ev); - } else { - /* - * This zone is not being managed; it has - * no task and can have no outstanding - * events. Free it immediately. - */ - /* - * Unmanaged zones should not have non-null views; - * we have no way of detaching from the view here - * without causing deadlock because this code is called - * with the view already locked. - */ - INSIST(zone->view == NULL); - free_now = ISC_TRUE; - } - UNLOCK_ZONE(zone); + result = dns_db_newversion(db, &ver); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "sync_keyzone:dns_db_newversion -> %s\n", + dns_result_totext(result)); + goto failure; } - *zonep = NULL; - if (free_now) - zone_free(zone); -} - -void -dns_zone_iattach(dns_zone_t *source, dns_zone_t **target) { - REQUIRE(DNS_ZONE_VALID(source)); - REQUIRE(target != NULL && *target == NULL); - LOCK_ZONE(source); - zone_iattach(source, target); - UNLOCK_ZONE(source); -} - -static void -zone_iattach(dns_zone_t *source, dns_zone_t **target) { /* - * 'source' locked by caller. + * Walk the zone DB. If we find any keys whose names are no longer + * in managed-keys (or *are* in trusted-keys, meaning they are + * permanent and not RFC5011-maintained), delete them from the + * zone. Otherwise call load_secroots(), which loads keys into + * secroots as appropriate. */ - REQUIRE(LOCKED_ZONE(source)); - REQUIRE(DNS_ZONE_VALID(source)); - REQUIRE(target != NULL && *target == NULL); - INSIST(source->irefs + isc_refcount_current(&source->erefs) > 0); - source->irefs++; - INSIST(source->irefs != 0); - *target = source; -} + dns_rriterator_init(&rrit, db, ver, 0); + for (result = dns_rriterator_first(&rrit); + result == ISC_R_SUCCESS; + result = dns_rriterator_nextrrset(&rrit)) { + dns_rdataset_t *rdataset; + dns_name_t *rrname = NULL; + isc_uint32_t ttl; + + dns_rriterator_current(&rrit, &rrname, &ttl, + &rdataset, NULL); + if (!dns_rdataset_isassociated(rdataset)) { + dns_rriterator_destroy(&rrit); + goto failure; + } -static void -zone_idetach(dns_zone_t **zonep) { - dns_zone_t *zone; + if (rdataset->type != dns_rdatatype_keydata) + continue; + + result = dns_keytable_find(sr, rrname, &keynode); + if ((result != ISC_R_SUCCESS && + result != DNS_R_PARTIALMATCH) || + dns_keynode_managed(keynode) == ISC_FALSE) { + CHECK(delete_keydata(db, ver, &diff, + rrname, rdataset)); + changed = ISC_TRUE; + } else { + load_secroots(zone, rrname, rdataset); + } + + if (keynode != NULL) + dns_keytable_detachkeynode(sr, &keynode); + } + dns_rriterator_destroy(&rrit); /* - * 'zone' locked by caller. + * Now walk secroots to find any managed keys that aren't + * in the zone. If we find any, we add them to the zone. */ - REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep)); - zone = *zonep; - REQUIRE(LOCKED_ZONE(*zonep)); - *zonep = NULL; - - INSIST(zone->irefs > 0); - zone->irefs--; - INSIST(zone->irefs + isc_refcount_current(&zone->erefs) > 0); -} + RWLOCK(&sr->rwlock, isc_rwlocktype_write); + dns_rbtnodechain_init(&chain, zone->mctx); + result = dns_rbtnodechain_first(&chain, sr->table, &foundname, origin); + if (result == ISC_R_NOTFOUND) + result = ISC_R_NOMORE; + while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) { + dns_rbtnode_t *rbtnode = NULL; + + dns_rbtnodechain_current(&chain, &foundname, origin, &rbtnode); + if (rbtnode->data == NULL) + goto skip; + + dns_keytable_attachkeynode(sr, rbtnode->data, &keynode); + if (dns_keynode_managed(keynode)) { + dns_fixedname_t fname; + dns_name_t *keyname; + dst_key_t *key; + + key = dns_keynode_key(keynode); + dns_fixedname_init(&fname); + + if (key == NULL) /* fail_secure() was called. */ + goto skip; + + keyname = dst_key_name(key); + result = dns_db_find(db, keyname, ver, + dns_rdatatype_keydata, + DNS_DBFIND_NOWILD, 0, NULL, + dns_fixedname_name(&fname), + NULL, NULL); + if (result != ISC_R_SUCCESS) + result = create_keydata(zone, db, ver, &diff, + sr, &keynode, &changed); + if (result != ISC_R_SUCCESS) + break; + } + skip: + result = dns_rbtnodechain_next(&chain, &foundname, origin); + if (keynode != NULL) + dns_keytable_detachkeynode(sr, &keynode); + } + RWUNLOCK(&sr->rwlock, isc_rwlocktype_write); -void -dns_zone_idetach(dns_zone_t **zonep) { - dns_zone_t *zone; - isc_boolean_t free_needed; + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; - REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep)); - zone = *zonep; - *zonep = NULL; + if (changed) { + /* Write changes to journal file. */ + result = increment_soa_serial(db, ver, &diff, zone->mctx); + if (result == ISC_R_SUCCESS) + zone_journal(zone, &diff, "sync_keyzone"); - LOCK_ZONE(zone); - INSIST(zone->irefs > 0); - zone->irefs--; - free_needed = exit_check(zone); - UNLOCK_ZONE(zone); - if (free_needed) - zone_free(zone); -} + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); + zone_needdump(zone, 30); + } -isc_mem_t * -dns_zone_getmctx(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); + failure: + if (keynode != NULL) + dns_keytable_detachkeynode(sr, &keynode); + if (sr != NULL) + dns_keytable_detach(&sr); + if (ver != NULL) + dns_db_closeversion(db, &ver, changed); + dns_diff_clear(&diff); - return (zone->mctx); + return (result); } -dns_zonemgr_t * -dns_zone_getmgr(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); +static isc_result_t +zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, + isc_result_t result) +{ + unsigned int soacount = 0; + unsigned int nscount = 0; + unsigned int errors = 0; + isc_uint32_t serial, oldserial, refresh, retry, expire, minimum; + isc_time_t now; + isc_boolean_t needdump = ISC_FALSE; + isc_boolean_t hasinclude = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE); + isc_boolean_t nomaster = ISC_FALSE; + unsigned int options; - return (zone->zmgr); -} + TIME_NOW(&now); -void -dns_zone_setflag(dns_zone_t *zone, unsigned int flags, isc_boolean_t value) { - REQUIRE(DNS_ZONE_VALID(zone)); + /* + * Initiate zone transfer? We may need a error code that + * indicates that the "permanent" form does not exist. + * XXX better error feedback to log. + */ + if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) { + if (zone->type == dns_zone_slave || + zone->type == dns_zone_stub) { + if (result == ISC_R_FILENOTFOUND) + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "no master file"); + else if (result != DNS_R_NOMASTERFILE) + dns_zone_log(zone, ISC_LOG_ERROR, + "loading from master file %s " + "failed: %s", + zone->masterfile, + dns_result_totext(result)); + } else { + dns_zone_log(zone, ISC_LOG_ERROR, + "loading from master file %s failed: %s", + zone->masterfile, + dns_result_totext(result)); + nomaster = ISC_TRUE; + } - LOCK_ZONE(zone); - if (value) - DNS_ZONE_SETFLAG(zone, flags); - else - DNS_ZONE_CLRFLAG(zone, flags); - UNLOCK_ZONE(zone); -} + if (zone->type != dns_zone_key) + goto cleanup; + } -void -dns_zone_setoption(dns_zone_t *zone, unsigned int option, isc_boolean_t value) -{ - REQUIRE(DNS_ZONE_VALID(zone)); + dns_zone_log(zone, ISC_LOG_DEBUG(2), + "number of nodes in database: %u", + dns_db_nodecount(db)); - LOCK_ZONE(zone); - if (value) - zone->options |= option; + if (result == DNS_R_SEENINCLUDE) + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HASINCLUDE); else - zone->options &= ~option; - UNLOCK_ZONE(zone); -} - -unsigned int -dns_zone_getoptions(dns_zone_t *zone) { - - REQUIRE(DNS_ZONE_VALID(zone)); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HASINCLUDE); - return (zone->options); -} + /* + * If there's no master file for a key zone, then the zone is new: + * create an SOA record. (We do this now, instead of later, so that + * if there happens to be a journal file, we can roll forward from + * a sane starting point.) + */ + if (nomaster && zone->type == dns_zone_key) { + result = add_soa(zone, db); + if (result != ISC_R_SUCCESS) + goto cleanup; + } -isc_result_t -dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) { - REQUIRE(DNS_ZONE_VALID(zone)); + /* + * Apply update log, if any, on initial load. + */ + if (zone->journal != NULL && + ! DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOMERGE) && + ! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) + { + if (zone->type == dns_zone_master && + (zone->update_acl != NULL || zone->ssutable != NULL)) + options = DNS_JOURNALOPT_RESIGN; + else + options = 0; + result = dns_journal_rollforward2(zone->mctx, db, options, + zone->sigresigninginterval, + zone->journal); + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND && + result != DNS_R_UPTODATE && result != DNS_R_NOJOURNAL && + result != ISC_R_RANGE) { + dns_zone_log(zone, ISC_LOG_ERROR, + "journal rollforward failed: %s", + dns_result_totext(result)); + goto cleanup; + } + if (result == ISC_R_NOTFOUND || result == ISC_R_RANGE) { + dns_zone_log(zone, ISC_LOG_ERROR, + "journal rollforward failed: " + "journal out of sync with zone"); + goto cleanup; + } + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "journal rollforward completed " + "successfully: %s", + dns_result_totext(result)); + if (result == ISC_R_SUCCESS) + needdump = ISC_TRUE; + } - LOCK_ZONE(zone); - zone->xfrsource4 = *xfrsource; - UNLOCK_ZONE(zone); + zone->loadtime = loadtime; - return (ISC_R_SUCCESS); -} + dns_zone_log(zone, ISC_LOG_DEBUG(1), "loaded"); + /* + * Obtain ns, soa and cname counts for top of zone. + */ + INSIST(db != NULL); + result = zone_get_from_db(zone, db, &nscount, &soacount, &serial, + &refresh, &retry, &expire, &minimum, + &errors); + if (result != ISC_R_SUCCESS && zone->type != dns_zone_key) { + dns_zone_log(zone, ISC_LOG_ERROR, + "could not find NS and/or SOA records"); + } -isc_sockaddr_t * -dns_zone_getxfrsource4(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); - return (&zone->xfrsource4); -} + /* + * Master / Slave / Stub zones require both NS and SOA records at + * the top of the zone. + */ -isc_result_t -dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) { - REQUIRE(DNS_ZONE_VALID(zone)); - - LOCK_ZONE(zone); - zone->xfrsource6 = *xfrsource; - UNLOCK_ZONE(zone); - - return (ISC_R_SUCCESS); -} - -isc_sockaddr_t * -dns_zone_getxfrsource6(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); - return (&zone->xfrsource6); -} - -isc_result_t -dns_zone_setaltxfrsource4(dns_zone_t *zone, - const isc_sockaddr_t *altxfrsource) -{ - REQUIRE(DNS_ZONE_VALID(zone)); - - LOCK_ZONE(zone); - zone->altxfrsource4 = *altxfrsource; - UNLOCK_ZONE(zone); + switch (zone->type) { + case dns_zone_dlz: + case dns_zone_master: + case dns_zone_slave: + case dns_zone_stub: + if (soacount != 1) { + dns_zone_log(zone, ISC_LOG_ERROR, + "has %d SOA records", soacount); + result = DNS_R_BADZONE; + } + if (nscount == 0) { + dns_zone_log(zone, ISC_LOG_ERROR, + "has no NS records"); + result = DNS_R_BADZONE; + } + if (result != ISC_R_SUCCESS) + goto cleanup; + if (zone->type == dns_zone_master && errors != 0) { + result = DNS_R_BADZONE; + goto cleanup; + } + if (zone->type != dns_zone_stub) { + result = check_nsec3param(zone, db); + if (result != ISC_R_SUCCESS) + goto cleanup; + } + if (zone->type == dns_zone_master && + DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKINTEGRITY) && + !integrity_checks(zone, db)) { + result = DNS_R_BADZONE; + goto cleanup; + } - return (ISC_R_SUCCESS); -} + if (zone->type == dns_zone_master && + DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKDUPRR) && + !zone_check_dup(zone, db)) { + result = DNS_R_BADZONE; + goto cleanup; + } -isc_sockaddr_t * -dns_zone_getaltxfrsource4(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); - return (&zone->altxfrsource4); -} + if (zone->db != NULL) { + /* + * This is checked in zone_replacedb() for slave zones + * as they don't reload from disk. + */ + result = zone_get_from_db(zone, zone->db, NULL, NULL, + &oldserial, NULL, NULL, NULL, + NULL, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) && + !isc_serial_gt(serial, oldserial)) { + isc_uint32_t serialmin, serialmax; -isc_result_t -dns_zone_setaltxfrsource6(dns_zone_t *zone, - const isc_sockaddr_t *altxfrsource) -{ - REQUIRE(DNS_ZONE_VALID(zone)); + INSIST(zone->type == dns_zone_master); - LOCK_ZONE(zone); - zone->altxfrsource6 = *altxfrsource; - UNLOCK_ZONE(zone); + serialmin = (oldserial + 1) & 0xffffffffU; + serialmax = (oldserial + 0x7fffffffU) & + 0xffffffffU; + dns_zone_log(zone, ISC_LOG_ERROR, + "ixfr-from-differences: " + "new serial (%u) out of range " + "[%u - %u]", serial, serialmin, + serialmax); + result = DNS_R_BADZONE; + goto cleanup; + } else if (!isc_serial_ge(serial, oldserial)) + dns_zone_log(zone, ISC_LOG_ERROR, + "zone serial (%u/%u) has gone " + "backwards", serial, oldserial); + else if (serial == oldserial && !hasinclude) + dns_zone_log(zone, ISC_LOG_ERROR, + "zone serial (%u) unchanged. " + "zone may fail to transfer " + "to slaves.", serial); + } - return (ISC_R_SUCCESS); -} + if (zone->type == dns_zone_master && + (zone->update_acl != NULL || zone->ssutable != NULL) && + zone->sigresigninginterval < (3 * refresh) && + dns_db_issecure(db)) + { + dns_zone_log(zone, ISC_LOG_WARNING, + "sig-re-signing-interval less than " + "3 * refresh."); + } -isc_sockaddr_t * -dns_zone_getaltxfrsource6(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); - return (&zone->altxfrsource6); -} + zone->refresh = RANGE(refresh, + zone->minrefresh, zone->maxrefresh); + zone->retry = RANGE(retry, + zone->minretry, zone->maxretry); + zone->expire = RANGE(expire, zone->refresh + zone->retry, + DNS_MAX_EXPIRE); + zone->minimum = minimum; + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS); -isc_result_t -dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) { - REQUIRE(DNS_ZONE_VALID(zone)); + if (zone->type == dns_zone_slave || + zone->type == dns_zone_stub) { + isc_time_t t; + isc_uint32_t delay; - LOCK_ZONE(zone); - zone->notifysrc4 = *notifysrc; - UNLOCK_ZONE(zone); + result = isc_file_getmodtime(zone->journal, &t); + if (result != ISC_R_SUCCESS) + result = isc_file_getmodtime(zone->masterfile, + &t); + if (result == ISC_R_SUCCESS) + DNS_ZONE_TIME_ADD(&t, zone->expire, + &zone->expiretime); + else + DNS_ZONE_TIME_ADD(&now, zone->retry, + &zone->expiretime); - return (ISC_R_SUCCESS); -} + delay = isc_random_jitter(zone->retry, + (zone->retry * 3) / 4); + DNS_ZONE_TIME_ADD(&now, delay, &zone->refreshtime); + if (isc_time_compare(&zone->refreshtime, + &zone->expiretime) >= 0) + zone->refreshtime = now; + } + break; -isc_sockaddr_t * -dns_zone_getnotifysrc4(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); - return (&zone->notifysrc4); -} + case dns_zone_key: + result = sync_keyzone(zone, db); + if (result != ISC_R_SUCCESS) + goto cleanup; + break; -isc_result_t -dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) { - REQUIRE(DNS_ZONE_VALID(zone)); + default: + UNEXPECTED_ERROR(__FILE__, __LINE__, + "unexpected zone type %d", zone->type); + result = ISC_R_UNEXPECTED; + goto cleanup; + } - LOCK_ZONE(zone); - zone->notifysrc6 = *notifysrc; - UNLOCK_ZONE(zone); + /* + * Check for weak DNSKEY's. + */ + if (zone->type == dns_zone_master) + zone_check_dnskeys(zone, db); - return (ISC_R_SUCCESS); -} + /* + * Schedule DNSSEC key refresh. + */ + if (zone->type == dns_zone_master && + DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN)) + zone->refreshkeytime = now; -isc_sockaddr_t * -dns_zone_getnotifysrc6(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); - return (&zone->notifysrc6); -} +#if 0 + /* destroy notification example. */ + { + isc_event_t *e = isc_event_allocate(zone->mctx, NULL, + DNS_EVENT_DBDESTROYED, + dns_zonemgr_dbdestroyed, + zone, + sizeof(isc_event_t)); + dns_db_ondestroy(db, zone->task, &e); + } +#endif -isc_result_t -dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify, - isc_uint32_t count) -{ - isc_sockaddr_t *new; + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); + if (zone->db != NULL) { + result = zone_replacedb(zone, db, ISC_FALSE); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); + if (result != ISC_R_SUCCESS) + goto cleanup; + } else { + zone_attachdb(zone, db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); + DNS_ZONE_SETFLAG(zone, + DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY); + } - REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(count == 0 || notify != NULL); + result = ISC_R_SUCCESS; - LOCK_ZONE(zone); - if (zone->notify != NULL) { - isc_mem_put(zone->mctx, zone->notify, - zone->notifycnt * sizeof(*new)); - zone->notify = NULL; - zone->notifycnt = 0; + if (needdump) { + if (zone->type == dns_zone_key) + zone_needdump(zone, 30); + else + zone_needdump(zone, DNS_DUMP_DELAY); } - if (count != 0) { - new = isc_mem_get(zone->mctx, count * sizeof(*new)); - if (new == NULL) { - UNLOCK_ZONE(zone); - return (ISC_R_NOMEMORY); + + if (zone->task != NULL) { + if (zone->type == dns_zone_master) { + set_resigntime(zone); + resume_signingwithkey(zone); + resume_addnsec3chain(zone); } - memcpy(new, notify, count * sizeof(*new)); - zone->notify = new; - zone->notifycnt = count; + zone_settimer(zone, &now); } - UNLOCK_ZONE(zone); - return (ISC_R_SUCCESS); -} -isc_result_t -dns_zone_setmasters(dns_zone_t *zone, const isc_sockaddr_t *masters, - isc_uint32_t count) -{ - isc_result_t result; + if (! dns_db_ispersistent(db)) + dns_zone_log(zone, ISC_LOG_INFO, "loaded serial %u%s", serial, + dns_db_issecure(db) ? " (DNSSEC signed)" : ""); - result = dns_zone_setmasterswithkeys(zone, masters, NULL, count); return (result); -} -static isc_boolean_t -same_masters(const isc_sockaddr_t *old, const isc_sockaddr_t *new, - isc_uint32_t count) -{ - unsigned int i; + cleanup: + if (zone->type == dns_zone_slave || + zone->type == dns_zone_stub || + zone->type == dns_zone_key) { + if (zone->journal != NULL) + zone_saveunique(zone, zone->journal, "jn-XXXXXXXX"); + if (zone->masterfile != NULL) + zone_saveunique(zone, zone->masterfile, "db-XXXXXXXX"); - for (i = 0; i < count; i++) - if (!isc_sockaddr_equal(&old[i], &new[i])) - return (ISC_FALSE); - return (ISC_TRUE); + /* Mark the zone for immediate refresh. */ + zone->refreshtime = now; + if (zone->task != NULL) + zone_settimer(zone, &now); + result = ISC_R_SUCCESS; + } else if (zone->type == dns_zone_master) + dns_zone_log(zone, ISC_LOG_ERROR, "not loaded due to errors."); + return (result); } static isc_boolean_t -same_keynames(dns_name_t **old, dns_name_t **new, isc_uint32_t count) { - unsigned int i; +exit_check(dns_zone_t *zone) { - if (old == NULL && new == NULL) - return (ISC_TRUE); - if (old == NULL || new == NULL) - return (ISC_FALSE); + REQUIRE(LOCKED_ZONE(zone)); - for (i = 0; i < count; i++) { - if (old[i] == NULL && new[i] == NULL) - continue; - if (old[i] == NULL || new[i] == NULL || - !dns_name_equal(old[i], new[i])) - return (ISC_FALSE); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SHUTDOWN) && + zone->irefs == 0) + { + /* + * DNS_ZONEFLG_SHUTDOWN can only be set if erefs == 0. + */ + INSIST(isc_refcount_current(&zone->erefs) == 0); + return (ISC_TRUE); } - return (ISC_TRUE); + return (ISC_FALSE); } -isc_result_t -dns_zone_setmasterswithkeys(dns_zone_t *zone, - const isc_sockaddr_t *masters, - dns_name_t **keynames, - isc_uint32_t count) +static isc_boolean_t +zone_check_ns(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, + dns_name_t *name, isc_boolean_t logit) { - isc_sockaddr_t *new; - isc_result_t result = ISC_R_SUCCESS; - dns_name_t **newname; - isc_boolean_t *newok; - unsigned int i; + isc_result_t result; + char namebuf[DNS_NAME_FORMATSIZE]; + char altbuf[DNS_NAME_FORMATSIZE]; + dns_fixedname_t fixed; + dns_name_t *foundname; + int level; - REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(count == 0 || masters != NULL); - if (keynames != NULL) { - REQUIRE(count != 0); - } + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOCHECKNS)) + return (ISC_TRUE); - LOCK_ZONE(zone); - /* - * The refresh code assumes that 'masters' wouldn't change under it. - * If it will change then kill off any current refresh in progress - * and update the masters info. If it won't change then we can just - * unlock and exit. - */ - if (count != zone->masterscnt || - !same_masters(zone->masters, masters, count) || - !same_keynames(zone->masterkeynames, keynames, count)) { - if (zone->request != NULL) - dns_request_cancel(zone->request); - } else - goto unlock; - if (zone->masters != NULL) { - isc_mem_put(zone->mctx, zone->masters, - zone->masterscnt * sizeof(*new)); - zone->masters = NULL; + if (zone->type == dns_zone_master) + level = ISC_LOG_ERROR; + else + level = ISC_LOG_WARNING; + + dns_fixedname_init(&fixed); + foundname = dns_fixedname_name(&fixed); + + result = dns_db_find(db, name, version, dns_rdatatype_a, + 0, 0, NULL, foundname, NULL, NULL); + if (result == ISC_R_SUCCESS) + return (ISC_TRUE); + + if (result == DNS_R_NXRRSET) { + result = dns_db_find(db, name, version, dns_rdatatype_aaaa, + 0, 0, NULL, foundname, NULL, NULL); + if (result == ISC_R_SUCCESS) + return (ISC_TRUE); } - if (zone->masterkeynames != NULL) { - for (i = 0; i < zone->masterscnt; i++) { - if (zone->masterkeynames[i] != NULL) { - dns_name_free(zone->masterkeynames[i], - zone->mctx); - isc_mem_put(zone->mctx, - zone->masterkeynames[i], - sizeof(dns_name_t)); - zone->masterkeynames[i] = NULL; - } + + if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN || + result == DNS_R_EMPTYNAME) { + if (logit) { + dns_name_format(name, namebuf, sizeof namebuf); + dns_zone_log(zone, level, "NS '%s' has no address " + "records (A or AAAA)", namebuf); } - isc_mem_put(zone->mctx, zone->masterkeynames, - zone->masterscnt * sizeof(dns_name_t *)); - zone->masterkeynames = NULL; - } - if (zone->mastersok != NULL) { - isc_mem_put(zone->mctx, zone->mastersok, - zone->masterscnt * sizeof(isc_boolean_t)); - zone->mastersok = NULL; + return (ISC_FALSE); } - zone->masterscnt = 0; - /* - * If count == 0, don't allocate any space for masters, mastersok or - * keynames so internally, those pointers are NULL if count == 0 - */ - if (count == 0) - goto unlock; - /* - * masters must contain count elements! - */ - new = isc_mem_get(zone->mctx, count * sizeof(*new)); - if (new == NULL) { - result = ISC_R_NOMEMORY; - goto unlock; + if (result == DNS_R_CNAME) { + if (logit) { + dns_name_format(name, namebuf, sizeof namebuf); + dns_zone_log(zone, level, "NS '%s' is a CNAME " + "(illegal)", namebuf); + } + return (ISC_FALSE); } - memcpy(new, masters, count * sizeof(*new)); - - /* - * Similarly for mastersok. - */ - newok = isc_mem_get(zone->mctx, count * sizeof(*newok)); - if (newok == NULL) { - result = ISC_R_NOMEMORY; - isc_mem_put(zone->mctx, new, count * sizeof(*new)); - goto unlock; - }; - for (i = 0; i < count; i++) - newok[i] = ISC_FALSE; - /* - * if keynames is non-NULL, it must contain count elements! - */ - newname = NULL; - if (keynames != NULL) { - newname = isc_mem_get(zone->mctx, count * sizeof(*newname)); - if (newname == NULL) { - result = ISC_R_NOMEMORY; - isc_mem_put(zone->mctx, new, count * sizeof(*new)); - isc_mem_put(zone->mctx, newok, count * sizeof(*newok)); - goto unlock; - } - for (i = 0; i < count; i++) - newname[i] = NULL; - for (i = 0; i < count; i++) { - if (keynames[i] != NULL) { - newname[i] = isc_mem_get(zone->mctx, - sizeof(dns_name_t)); - if (newname[i] == NULL) - goto allocfail; - dns_name_init(newname[i], NULL); - result = dns_name_dup(keynames[i], zone->mctx, - newname[i]); - if (result != ISC_R_SUCCESS) { - allocfail: - for (i = 0; i < count; i++) - if (newname[i] != NULL) - dns_name_free( - newname[i], - zone->mctx); - isc_mem_put(zone->mctx, new, - count * sizeof(*new)); - isc_mem_put(zone->mctx, newok, - count * sizeof(*newok)); - isc_mem_put(zone->mctx, newname, - count * sizeof(*newname)); - goto unlock; - } - } + if (result == DNS_R_DNAME) { + if (logit) { + dns_name_format(name, namebuf, sizeof namebuf); + dns_name_format(foundname, altbuf, sizeof altbuf); + dns_zone_log(zone, level, "NS '%s' is below a DNAME " + "'%s' (illegal)", namebuf, altbuf); } + return (ISC_FALSE); } - /* - * Everything is ok so attach to the zone. - */ - zone->masters = new; - zone->mastersok = newok; - zone->masterkeynames = newname; - zone->masterscnt = count; - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOMASTERS); - - unlock: - UNLOCK_ZONE(zone); - return (result); -} - -isc_result_t -dns_zone_getdb(dns_zone_t *zone, dns_db_t **dpb) { - isc_result_t result = ISC_R_SUCCESS; - - REQUIRE(DNS_ZONE_VALID(zone)); - - ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); - if (zone->db == NULL) - result = DNS_R_NOTLOADED; - else - dns_db_attach(zone->db, dpb); - ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); - - return (result); + return (ISC_TRUE); } -/* - * Co-ordinates the starting of routine jobs. - */ +static isc_result_t +zone_count_ns_rr(dns_zone_t *zone, dns_db_t *db, dns_dbnode_t *node, + dns_dbversion_t *version, unsigned int *nscount, + unsigned int *errors, isc_boolean_t logit) +{ + isc_result_t result; + unsigned int count = 0; + unsigned int ecount = 0; + dns_rdataset_t rdataset; + dns_rdata_t rdata; + dns_rdata_ns_t ns; -void -dns_zone_maintenance(dns_zone_t *zone) { - const char me[] = "dns_zone_maintenance"; - isc_time_t now; + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, version, dns_rdatatype_ns, + dns_rdatatype_none, 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) { + INSIST(!dns_rdataset_isassociated(&rdataset)); + goto success; + } + if (result != ISC_R_SUCCESS) { + INSIST(!dns_rdataset_isassociated(&rdataset)); + goto invalidate_rdataset; + } - REQUIRE(DNS_ZONE_VALID(zone)); - ENTER; + result = dns_rdataset_first(&rdataset); + while (result == ISC_R_SUCCESS) { + if (errors != NULL && zone->rdclass == dns_rdataclass_in && + (zone->type == dns_zone_master || + zone->type == dns_zone_slave)) { + dns_rdata_init(&rdata); + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &ns, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (dns_name_issubdomain(&ns.name, &zone->origin) && + !zone_check_ns(zone, db, version, &ns.name, logit)) + ecount++; + } + count++; + result = dns_rdataset_next(&rdataset); + } + dns_rdataset_disassociate(&rdataset); - LOCK_ZONE(zone); - TIME_NOW(&now); - zone_settimer(zone, &now); - UNLOCK_ZONE(zone); -} + success: + if (nscount != NULL) + *nscount = count; + if (errors != NULL) + *errors = ecount; -static inline isc_boolean_t -was_dumping(dns_zone_t *zone) { - isc_boolean_t dumping; + result = ISC_R_SUCCESS; - REQUIRE(LOCKED_ZONE(zone)); + invalidate_rdataset: + dns_rdataset_invalidate(&rdataset); - dumping = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING); - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING); - if (!dumping) { - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP); - isc_time_settoepoch(&zone->dumptime); - } - return (dumping); + return (result); } -#define MAXZONEKEYS 10 - static isc_result_t -do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver, - dns_diff_t *diff) +zone_load_soa_rr(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + unsigned int *soacount, + isc_uint32_t *serial, isc_uint32_t *refresh, + isc_uint32_t *retry, isc_uint32_t *expire, + isc_uint32_t *minimum) { - dns_diff_t temp_diff; isc_result_t result; + unsigned int count; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_soa_t soa; - /* - * Create a singleton diff. - */ - dns_diff_init(diff->mctx, &temp_diff); - temp_diff.resign = diff->resign; - ISC_LIST_APPEND(temp_diff.tuples, *tuple, link); - - /* - * Apply it to the database. - */ - result = dns_diff_apply(&temp_diff, db, ver); - ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link); + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa, + dns_rdatatype_none, 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) { + INSIST(!dns_rdataset_isassociated(&rdataset)); + if (soacount != NULL) + *soacount = 0; + if (serial != NULL) + *serial = 0; + if (refresh != NULL) + *refresh = 0; + if (retry != NULL) + *retry = 0; + if (expire != NULL) + *expire = 0; + if (minimum != NULL) + *minimum = 0; + result = ISC_R_SUCCESS; + goto invalidate_rdataset; + } if (result != ISC_R_SUCCESS) { - dns_difftuple_free(tuple); - return (result); + INSIST(!dns_rdataset_isassociated(&rdataset)); + goto invalidate_rdataset; } - /* - * Merge it into the current pending journal entry. - */ - dns_diff_appendminimal(diff, tuple); - - /* - * Do not clear temp_diff. - */ - return (ISC_R_SUCCESS); -} - -static isc_result_t -increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver, - dns_diff_t *diff, isc_mem_t *mctx) -{ - dns_difftuple_t *deltuple = NULL; - dns_difftuple_t *addtuple = NULL; - isc_uint32_t serial; - isc_result_t result; + count = 0; + result = dns_rdataset_first(&rdataset); + while (result == ISC_R_SUCCESS) { + dns_rdata_init(&rdata); + dns_rdataset_current(&rdataset, &rdata); + count++; + if (count == 1) { + result = dns_rdata_tostruct(&rdata, &soa, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + } - CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple)); - CHECK(dns_difftuple_copy(deltuple, &addtuple)); - addtuple->op = DNS_DIFFOP_ADD; + result = dns_rdataset_next(&rdataset); + dns_rdata_reset(&rdata); + } + dns_rdataset_disassociate(&rdataset); - serial = dns_soa_getserial(&addtuple->rdata); + if (soacount != NULL) + *soacount = count; - /* RFC1982 */ - serial = (serial + 1) & 0xFFFFFFFF; - if (serial == 0) - serial = 1; + if (count > 0) { + if (serial != NULL) + *serial = soa.serial; + if (refresh != NULL) + *refresh = soa.refresh; + if (retry != NULL) + *retry = soa.retry; + if (expire != NULL) + *expire = soa.expire; + if (minimum != NULL) + *minimum = soa.minimum; + } - dns_soa_setserial(serial, &addtuple->rdata); - CHECK(do_one_tuple(&deltuple, db, ver, diff)); - CHECK(do_one_tuple(&addtuple, db, ver, diff)); result = ISC_R_SUCCESS; - failure: - if (addtuple != NULL) - dns_difftuple_free(&addtuple); - if (deltuple != NULL) - dns_difftuple_free(&deltuple); + invalidate_rdataset: + dns_rdataset_invalidate(&rdataset); + return (result); } +/* + * zone must be locked. + */ static isc_result_t -update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, - dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl, - dns_rdata_t *rdata) +zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount, + unsigned int *soacount, isc_uint32_t *serial, + isc_uint32_t *refresh, isc_uint32_t *retry, + isc_uint32_t *expire, isc_uint32_t *minimum, + unsigned int *errors) { - dns_difftuple_t *tuple = NULL; isc_result_t result; - result = dns_difftuple_create(diff->mctx, op, - name, ttl, rdata, &tuple); - if (result != ISC_R_SUCCESS) - return (result); - return (do_one_tuple(&tuple, db, ver, diff)); -} + isc_result_t answer = ISC_R_SUCCESS; + dns_dbversion_t *version = NULL; + dns_dbnode_t *node; -static isc_boolean_t -ksk_sanity(dns_db_t *db, dns_dbversion_t *ver) { - isc_boolean_t ret = ISC_FALSE; - isc_boolean_t have_ksk = ISC_FALSE, have_nonksk = ISC_FALSE; - isc_result_t result; - dns_dbnode_t *node = NULL; - dns_rdataset_t rdataset; - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdata_dnskey_t dnskey; + REQUIRE(db != NULL); + REQUIRE(zone != NULL); - dns_rdataset_init(&rdataset); - CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); - CHECK(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0, - &rdataset, NULL)); - CHECK(dns_rdataset_first(&rdataset)); - while (result == ISC_R_SUCCESS && (!have_ksk || !have_nonksk)) { - dns_rdataset_current(&rdataset, &rdata); - CHECK(dns_rdata_tostruct(&rdata, &dnskey, NULL)); - if ((dnskey.flags & (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH)) - == DNS_KEYOWNER_ZONE) { - if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0) - have_ksk = ISC_TRUE; - else - have_nonksk = ISC_TRUE; - } - dns_rdata_reset(&rdata); - result = dns_rdataset_next(&rdataset); + dns_db_currentversion(db, &version); + + node = NULL; + result = dns_db_findnode(db, &zone->origin, ISC_FALSE, &node); + if (result != ISC_R_SUCCESS) { + answer = result; + goto closeversion; } - if (have_ksk && have_nonksk) - ret = ISC_TRUE; - failure: - if (dns_rdataset_isassociated(&rdataset)) - dns_rdataset_disassociate(&rdataset); - if (node != NULL) - dns_db_detachnode(db, &node); - return (ret); -} -static isc_result_t -find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, - isc_mem_t *mctx, unsigned int maxkeys, - dst_key_t **keys, unsigned int *nkeys) -{ - isc_result_t result; - dns_dbnode_t *node = NULL; - const char *directory = dns_zone_getkeydirectory(zone); + if (nscount != NULL || errors != NULL) { + result = zone_count_ns_rr(zone, db, node, version, + nscount, errors, ISC_TRUE); + if (result != ISC_R_SUCCESS) + answer = result; + } - CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); - result = dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db), - directory, mctx, maxkeys, keys, - nkeys); - if (result == ISC_R_NOTFOUND) - result = ISC_R_SUCCESS; - failure: - if (node != NULL) - dns_db_detachnode(db, &node); - return (result); + if (soacount != NULL || serial != NULL || refresh != NULL + || retry != NULL || expire != NULL || minimum != NULL) { + result = zone_load_soa_rr(db, node, version, soacount, + serial, refresh, retry, expire, + minimum); + if (result != ISC_R_SUCCESS) + answer = result; + } + + dns_db_detachnode(db, &node); + closeversion: + dns_db_closeversion(db, &version, ISC_FALSE); + + return (answer); } -static isc_result_t -offline(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, dns_name_t *name, - dns_ttl_t ttl, dns_rdata_t *rdata) -{ - isc_result_t result; +void +dns_zone_attach(dns_zone_t *source, dns_zone_t **target) { + REQUIRE(DNS_ZONE_VALID(source)); + REQUIRE(target != NULL && *target == NULL); + isc_refcount_increment(&source->erefs, NULL); + *target = source; +} + +void +dns_zone_detach(dns_zone_t **zonep) { + dns_zone_t *zone; + unsigned int refs; + isc_boolean_t free_now = ISC_FALSE; + + REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep)); + + zone = *zonep; + + isc_refcount_decrement(&zone->erefs, &refs); + + if (refs == 0) { + LOCK_ZONE(zone); + /* + * We just detached the last external reference. + */ + if (zone->task != NULL) { + /* + * This zone is being managed. Post + * its control event and let it clean + * up synchronously in the context of + * its task. + */ + isc_event_t *ev = &zone->ctlevent; + isc_task_send(zone->task, &ev); + } else { + /* + * This zone is not being managed; it has + * no task and can have no outstanding + * events. Free it immediately. + */ + /* + * Unmanaged zones should not have non-null views; + * we have no way of detaching from the view here + * without causing deadlock because this code is called + * with the view already locked. + */ + INSIST(zone->view == NULL); + free_now = ISC_TRUE; + } + UNLOCK_ZONE(zone); + } + *zonep = NULL; + if (free_now) + zone_free(zone); +} + +void +dns_zone_iattach(dns_zone_t *source, dns_zone_t **target) { + REQUIRE(DNS_ZONE_VALID(source)); + REQUIRE(target != NULL && *target == NULL); + LOCK_ZONE(source); + zone_iattach(source, target); + UNLOCK_ZONE(source); +} + +static void +zone_iattach(dns_zone_t *source, dns_zone_t **target) { + + /* + * 'source' locked by caller. + */ + REQUIRE(LOCKED_ZONE(source)); + REQUIRE(DNS_ZONE_VALID(source)); + REQUIRE(target != NULL && *target == NULL); + INSIST(source->irefs + isc_refcount_current(&source->erefs) > 0); + source->irefs++; + INSIST(source->irefs != 0); + *target = source; +} + +static void +zone_idetach(dns_zone_t **zonep) { + dns_zone_t *zone; + + /* + * 'zone' locked by caller. + */ + REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep)); + zone = *zonep; + REQUIRE(LOCKED_ZONE(*zonep)); + *zonep = NULL; + + INSIST(zone->irefs > 0); + zone->irefs--; + INSIST(zone->irefs + isc_refcount_current(&zone->erefs) > 0); +} + +void +dns_zone_idetach(dns_zone_t **zonep) { + dns_zone_t *zone; + isc_boolean_t free_needed; + + REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep)); + zone = *zonep; + *zonep = NULL; + + LOCK_ZONE(zone); + INSIST(zone->irefs > 0); + zone->irefs--; + free_needed = exit_check(zone); + UNLOCK_ZONE(zone); + if (free_needed) + zone_free(zone); +} + +isc_mem_t * +dns_zone_getmctx(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + + return (zone->mctx); +} + +dns_zonemgr_t * +dns_zone_getmgr(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + + return (zone->zmgr); +} + +void +dns_zone_setflag(dns_zone_t *zone, unsigned int flags, isc_boolean_t value) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + if (value) + DNS_ZONE_SETFLAG(zone, flags); + else + DNS_ZONE_CLRFLAG(zone, flags); + UNLOCK_ZONE(zone); +} + +void +dns_zone_setoption(dns_zone_t *zone, unsigned int option, isc_boolean_t value) +{ + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + if (value) + zone->options |= option; + else + zone->options &= ~option; + UNLOCK_ZONE(zone); +} + +unsigned int +dns_zone_getoptions(dns_zone_t *zone) { + + REQUIRE(DNS_ZONE_VALID(zone)); + + return (zone->options); +} + +void +dns_zone_setkeyopt(dns_zone_t *zone, unsigned int keyopt, isc_boolean_t value) +{ + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + if (value) + zone->keyopts |= keyopt; + else + zone->keyopts &= ~keyopt; + UNLOCK_ZONE(zone); +} + +unsigned int +dns_zone_getkeyopts(dns_zone_t *zone) { + + REQUIRE(DNS_ZONE_VALID(zone)); + + return (zone->keyopts); +} + +isc_result_t +dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + zone->xfrsource4 = *xfrsource; + UNLOCK_ZONE(zone); + + return (ISC_R_SUCCESS); +} + +isc_sockaddr_t * +dns_zone_getxfrsource4(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (&zone->xfrsource4); +} + +isc_result_t +dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + zone->xfrsource6 = *xfrsource; + UNLOCK_ZONE(zone); + + return (ISC_R_SUCCESS); +} + +isc_sockaddr_t * +dns_zone_getxfrsource6(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (&zone->xfrsource6); +} + +isc_result_t +dns_zone_setaltxfrsource4(dns_zone_t *zone, + const isc_sockaddr_t *altxfrsource) +{ + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + zone->altxfrsource4 = *altxfrsource; + UNLOCK_ZONE(zone); + + return (ISC_R_SUCCESS); +} + +isc_sockaddr_t * +dns_zone_getaltxfrsource4(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (&zone->altxfrsource4); +} + +isc_result_t +dns_zone_setaltxfrsource6(dns_zone_t *zone, + const isc_sockaddr_t *altxfrsource) +{ + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + zone->altxfrsource6 = *altxfrsource; + UNLOCK_ZONE(zone); + + return (ISC_R_SUCCESS); +} + +isc_sockaddr_t * +dns_zone_getaltxfrsource6(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (&zone->altxfrsource6); +} + +isc_result_t +dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + zone->notifysrc4 = *notifysrc; + UNLOCK_ZONE(zone); + + return (ISC_R_SUCCESS); +} + +isc_sockaddr_t * +dns_zone_getnotifysrc4(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (&zone->notifysrc4); +} + +isc_result_t +dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + zone->notifysrc6 = *notifysrc; + UNLOCK_ZONE(zone); + + return (ISC_R_SUCCESS); +} + +isc_sockaddr_t * +dns_zone_getnotifysrc6(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (&zone->notifysrc6); +} + +isc_result_t +dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify, + isc_uint32_t count) +{ + isc_sockaddr_t *new; + + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(count == 0 || notify != NULL); + + LOCK_ZONE(zone); + if (zone->notify != NULL) { + isc_mem_put(zone->mctx, zone->notify, + zone->notifycnt * sizeof(*new)); + zone->notify = NULL; + zone->notifycnt = 0; + } + if (count != 0) { + new = isc_mem_get(zone->mctx, count * sizeof(*new)); + if (new == NULL) { + UNLOCK_ZONE(zone); + return (ISC_R_NOMEMORY); + } + memcpy(new, notify, count * sizeof(*new)); + zone->notify = new; + zone->notifycnt = count; + } + UNLOCK_ZONE(zone); + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_zone_setmasters(dns_zone_t *zone, const isc_sockaddr_t *masters, + isc_uint32_t count) +{ + isc_result_t result; + + result = dns_zone_setmasterswithkeys(zone, masters, NULL, count); + return (result); +} + +static isc_boolean_t +same_masters(const isc_sockaddr_t *old, const isc_sockaddr_t *new, + isc_uint32_t count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + if (!isc_sockaddr_equal(&old[i], &new[i])) + return (ISC_FALSE); + return (ISC_TRUE); +} + +static isc_boolean_t +same_keynames(dns_name_t **old, dns_name_t **new, isc_uint32_t count) { + unsigned int i; + + if (old == NULL && new == NULL) + return (ISC_TRUE); + if (old == NULL || new == NULL) + return (ISC_FALSE); + + for (i = 0; i < count; i++) { + if (old[i] == NULL && new[i] == NULL) + continue; + if (old[i] == NULL || new[i] == NULL || + !dns_name_equal(old[i], new[i])) + return (ISC_FALSE); + } + return (ISC_TRUE); +} + +isc_result_t +dns_zone_setmasterswithkeys(dns_zone_t *zone, + const isc_sockaddr_t *masters, + dns_name_t **keynames, + isc_uint32_t count) +{ + isc_sockaddr_t *new; + isc_result_t result = ISC_R_SUCCESS; + dns_name_t **newname; + isc_boolean_t *newok; + unsigned int i; + + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(count == 0 || masters != NULL); + if (keynames != NULL) { + REQUIRE(count != 0); + } + + LOCK_ZONE(zone); + /* + * The refresh code assumes that 'masters' wouldn't change under it. + * If it will change then kill off any current refresh in progress + * and update the masters info. If it won't change then we can just + * unlock and exit. + */ + if (count != zone->masterscnt || + !same_masters(zone->masters, masters, count) || + !same_keynames(zone->masterkeynames, keynames, count)) { + if (zone->request != NULL) + dns_request_cancel(zone->request); + } else + goto unlock; + if (zone->masters != NULL) { + isc_mem_put(zone->mctx, zone->masters, + zone->masterscnt * sizeof(*new)); + zone->masters = NULL; + } + if (zone->masterkeynames != NULL) { + for (i = 0; i < zone->masterscnt; i++) { + if (zone->masterkeynames[i] != NULL) { + dns_name_free(zone->masterkeynames[i], + zone->mctx); + isc_mem_put(zone->mctx, + zone->masterkeynames[i], + sizeof(dns_name_t)); + zone->masterkeynames[i] = NULL; + } + } + isc_mem_put(zone->mctx, zone->masterkeynames, + zone->masterscnt * sizeof(dns_name_t *)); + zone->masterkeynames = NULL; + } + if (zone->mastersok != NULL) { + isc_mem_put(zone->mctx, zone->mastersok, + zone->masterscnt * sizeof(isc_boolean_t)); + zone->mastersok = NULL; + } + zone->masterscnt = 0; + /* + * If count == 0, don't allocate any space for masters, mastersok or + * keynames so internally, those pointers are NULL if count == 0 + */ + if (count == 0) + goto unlock; + + /* + * masters must contain count elements! + */ + new = isc_mem_get(zone->mctx, count * sizeof(*new)); + if (new == NULL) { + result = ISC_R_NOMEMORY; + goto unlock; + } + memcpy(new, masters, count * sizeof(*new)); + + /* + * Similarly for mastersok. + */ + newok = isc_mem_get(zone->mctx, count * sizeof(*newok)); + if (newok == NULL) { + result = ISC_R_NOMEMORY; + isc_mem_put(zone->mctx, new, count * sizeof(*new)); + goto unlock; + }; + for (i = 0; i < count; i++) + newok[i] = ISC_FALSE; + + /* + * if keynames is non-NULL, it must contain count elements! + */ + newname = NULL; + if (keynames != NULL) { + newname = isc_mem_get(zone->mctx, count * sizeof(*newname)); + if (newname == NULL) { + result = ISC_R_NOMEMORY; + isc_mem_put(zone->mctx, new, count * sizeof(*new)); + isc_mem_put(zone->mctx, newok, count * sizeof(*newok)); + goto unlock; + } + for (i = 0; i < count; i++) + newname[i] = NULL; + for (i = 0; i < count; i++) { + if (keynames[i] != NULL) { + newname[i] = isc_mem_get(zone->mctx, + sizeof(dns_name_t)); + if (newname[i] == NULL) + goto allocfail; + dns_name_init(newname[i], NULL); + result = dns_name_dup(keynames[i], zone->mctx, + newname[i]); + if (result != ISC_R_SUCCESS) { + allocfail: + for (i = 0; i < count; i++) + if (newname[i] != NULL) + dns_name_free( + newname[i], + zone->mctx); + isc_mem_put(zone->mctx, new, + count * sizeof(*new)); + isc_mem_put(zone->mctx, newok, + count * sizeof(*newok)); + isc_mem_put(zone->mctx, newname, + count * sizeof(*newname)); + goto unlock; + } + } + } + } + + /* + * Everything is ok so attach to the zone. + */ + zone->masters = new; + zone->mastersok = newok; + zone->masterkeynames = newname; + zone->masterscnt = count; + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOMASTERS); + + unlock: + UNLOCK_ZONE(zone); + return (result); +} + +isc_result_t +dns_zone_getdb(dns_zone_t *zone, dns_db_t **dpb) { + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(DNS_ZONE_VALID(zone)); + + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + if (zone->db == NULL) + result = DNS_R_NOTLOADED; + else + dns_db_attach(zone->db, dpb); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + + return (result); +} + +void +dns_zone_setdb(dns_zone_t *zone, dns_db_t *db) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(zone->type == dns_zone_staticstub); + + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); + REQUIRE(zone->db == NULL); + dns_db_attach(db, &zone->db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); +} + +/* + * Co-ordinates the starting of routine jobs. + */ + +void +dns_zone_maintenance(dns_zone_t *zone) { + const char me[] = "dns_zone_maintenance"; + isc_time_t now; + + REQUIRE(DNS_ZONE_VALID(zone)); + ENTER; + + LOCK_ZONE(zone); + TIME_NOW(&now); + zone_settimer(zone, &now); + UNLOCK_ZONE(zone); +} + +static inline isc_boolean_t +was_dumping(dns_zone_t *zone) { + isc_boolean_t dumping; + + REQUIRE(LOCKED_ZONE(zone)); + + dumping = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING); + if (!dumping) { + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP); + isc_time_settoepoch(&zone->dumptime); + } + return (dumping); +} + +#define MAXZONEKEYS 10 + +static isc_result_t +find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, + isc_mem_t *mctx, unsigned int maxkeys, + dst_key_t **keys, unsigned int *nkeys) +{ + isc_result_t result; + dns_dbnode_t *node = NULL; + const char *directory = dns_zone_getkeydirectory(zone); + + CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); + result = dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db), + directory, mctx, maxkeys, keys, + nkeys); + if (result == ISC_R_NOTFOUND) + result = ISC_R_SUCCESS; + failure: + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); +} + +static isc_result_t +offline(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, dns_name_t *name, + dns_ttl_t ttl, dns_rdata_t *rdata) +{ + isc_result_t result; if ((rdata->flags & DNS_RDATA_OFFLINE) != 0) return (ISC_R_SUCCESS); @@ -3752,10 +4575,14 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, (isc_stdtime_t) 0, &rdataset, NULL); dns_db_detachnode(db, &node); - if (result == ISC_R_NOTFOUND) + if (result == ISC_R_NOTFOUND) { + INSIST(!dns_rdataset_isassociated(&rdataset)); return (ISC_R_SUCCESS); - if (result != ISC_R_SUCCESS) + } + if (result != ISC_R_SUCCESS) { + INSIST(!dns_rdataset_isassociated(&rdataset)); goto failure; + } for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; @@ -3841,7 +4668,8 @@ static isc_result_t add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys, isc_mem_t *mctx, isc_stdtime_t inception, - isc_stdtime_t expire, isc_boolean_t check_ksk) + isc_stdtime_t expire, isc_boolean_t check_ksk, + isc_boolean_t keyset_kskonly) { isc_result_t result; dns_dbnode_t *node = NULL; @@ -3849,7 +4677,7 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_rdata_t sig_rdata = DNS_RDATA_INIT; unsigned char data[1024]; /* XXX */ isc_buffer_t buffer; - unsigned int i; + unsigned int i, j; dns_rdataset_init(&rdataset); isc_buffer_init(&buffer, data, sizeof(data)); @@ -3865,18 +4693,59 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, result = dns_db_findrdataset(db, node, ver, type, 0, (isc_stdtime_t) 0, &rdataset, NULL); dns_db_detachnode(db, &node); - if (result == ISC_R_NOTFOUND) + if (result == ISC_R_NOTFOUND) { + INSIST(!dns_rdataset_isassociated(&rdataset)); return (ISC_R_SUCCESS); - if (result != ISC_R_SUCCESS) + } + if (result != ISC_R_SUCCESS) { + INSIST(!dns_rdataset_isassociated(&rdataset)); goto failure; + } + +#define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0) +#define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0) +#define ALG(x) dst_key_alg(x) for (i = 0; i < nkeys; i++) { - if (check_ksk && type != dns_rdatatype_dnskey && - (dst_key_flags(keys[i]) & DNS_KEYFLAG_KSK) != 0) - continue; + isc_boolean_t both = ISC_FALSE; + if (!dst_key_isprivate(keys[i])) continue; + + if (check_ksk && !REVOKE(keys[i])) { + isc_boolean_t have_ksk, have_nonksk; + if (KSK(keys[i])) { + have_ksk = ISC_TRUE; + have_nonksk = ISC_FALSE; + } else { + have_ksk = ISC_FALSE; + have_nonksk = ISC_TRUE; + } + for (j = 0; j < nkeys; j++) { + if (j == i || ALG(keys[i]) != ALG(keys[j])) + continue; + if (REVOKE(keys[j])) + continue; + if (KSK(keys[j])) + have_ksk = ISC_TRUE; + else + have_nonksk = ISC_TRUE; + both = have_ksk && have_nonksk; + if (both) + break; + } + } + if (both) { + if (type == dns_rdatatype_dnskey) { + if (!KSK(keys[i]) && keyset_kskonly) + continue; + } else if (KSK(keys[i])) + continue; + } else if (REVOKE(keys[i]) && type != dns_rdatatype_dnskey) + continue; + /* Calculate the signature, creating a RRSIG RDATA. */ + isc_buffer_clear(&buffer); CHECK(dns_dnssec_sign(name, &rdataset, keys[i], &inception, &expire, mctx, &buffer, &sig_rdata)); @@ -3898,7 +4767,6 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, static void zone_resigninc(dns_zone_t *zone) { - const char *journalfile; dns_db_t *db = NULL; dns_dbversion_t *version = NULL; dns_diff_t sig_diff; @@ -3907,7 +4775,7 @@ zone_resigninc(dns_zone_t *zone) { dns_rdataset_t rdataset; dns_rdatatype_t covers; dst_key_t *zone_keys[MAXZONEKEYS]; - isc_boolean_t check_ksk; + isc_boolean_t check_ksk, keyset_kskonly = ISC_FALSE; isc_result_t result; isc_stdtime_t now, inception, soaexpire, expire, stop; isc_uint32_t jitter; @@ -3962,8 +4830,7 @@ zone_resigninc(dns_zone_t *zone) { stop = now + 5; check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); - if (check_ksk) - check_ksk = ksk_sanity(db, version); + keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY); name = dns_fixedname_name(&fixed); result = dns_db_getsigningtime(db, &rdataset, name); @@ -4007,14 +4874,14 @@ zone_resigninc(dns_zone_t *zone) { } result = add_sigs(db, version, name, covers, &sig_diff, zone_keys, nkeys, zone->mctx, inception, - expire, check_ksk); + expire, check_ksk, keyset_kskonly); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, "zone_resigninc:add_sigs -> %s\n", dns_result_totext(result)); break; } - result = dns_db_getsigningtime(db, &rdataset, + result = dns_db_getsigningtime(db, &rdataset, dns_fixedname_name(&fixed)); if (nkeys == 0 && result == ISC_R_NOTFOUND) { result = ISC_R_SUCCESS; @@ -4052,7 +4919,7 @@ zone_resigninc(dns_zone_t *zone) { */ result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa, &sig_diff, zone_keys, nkeys, zone->mctx, inception, - soaexpire, check_ksk); + soaexpire, check_ksk, keyset_kskonly); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, "zone_resigninc:add_sigs -> %s\n", @@ -4060,31 +4927,10 @@ zone_resigninc(dns_zone_t *zone) { goto failure; } - journalfile = dns_zone_getjournal(zone); - if (journalfile != NULL) { - dns_journal_t *journal = NULL; - result = dns_journal_open(zone->mctx, journalfile, - ISC_TRUE, &journal); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_resigninc:dns_journal_open -> %s\n", - dns_result_totext(result)); - goto failure; - } - - result = dns_journal_write_transaction(journal, &sig_diff); - dns_journal_destroy(&journal); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_resigninc:dns_journal_write_transaction -> %s\n", - dns_result_totext(result)); - goto failure; - } - } + /* Write changes to journal file. */ + zone_journal(zone, &sig_diff, "zone_resigninc"); - /* - * Everything has succeeded. Commit the changes. - */ + /* Everything has succeeded. Commit the changes. */ dns_db_closeversion(db, &version, ISC_TRUE); failure: @@ -4151,16 +4997,6 @@ next_active(dns_db_t *db, dns_dbversion_t *version, dns_name_t *oldname, return (result); } -static void -set_bit(unsigned char *array, unsigned int index) { - unsigned int shift, mask; - - shift = 7 - (index % 8); - mask = 1 << shift; - - array[index / 8] |= mask; -} - static isc_boolean_t signed_with_key(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_rdatatype_t type, dst_key_t *key) @@ -4173,8 +5009,10 @@ signed_with_key(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_rdataset_init(&rdataset); result = dns_db_findrdataset(db, node, version, dns_rdatatype_rrsig, type, 0, &rdataset, NULL); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + INSIST(!dns_rdataset_isassociated(&rdataset)); return (ISC_FALSE); + } for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(&rdataset)) { @@ -4209,21 +5047,6 @@ add_nsec(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, CHECK(next_active(db, version, name, next, bottom)); CHECK(dns_nsec_buildrdata(db, version, node, next, nsecbuffer, &rdata)); - if (dns_name_equal(dns_db_origin(db), name)) { - /* - * Set the OPT bit to indicate that this is a - * partially secure zone. - */ - isc_region_t region; - - dns_rdata_toregion(&rdata, ®ion); - dns_name_fromregion(next, ®ion); - isc_region_consume(®ion, next->length); - INSIST(region.length > (2 + dns_rdatatype_opt / 8) && - region.base[0] == 0 && - region.base[1] > dns_rdatatype_opt / 8); - set_bit(region.base + 2, dns_rdatatype_opt); - } CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name, ttl, &rdata)); failure: @@ -4236,8 +5059,8 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node, isc_boolean_t build_nsec, dst_key_t *key, isc_stdtime_t inception, isc_stdtime_t expire, unsigned int minimum, isc_boolean_t is_ksk, - isc_boolean_t *delegation, dns_diff_t *diff, - isc_int32_t *signatures, isc_mem_t *mctx) + isc_boolean_t keyset_kskonly, isc_boolean_t *delegation, + dns_diff_t *diff, isc_int32_t *signatures, isc_mem_t *mctx) { isc_result_t result; dns_rdatasetiter_t *iterator = NULL; @@ -4255,6 +5078,7 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node, result = ISC_R_SUCCESS; return (result); } + dns_rdataset_init(&rdataset); isc_buffer_init(&buffer, data, sizeof(data)); seen_rr = seen_soa = seen_ns = seen_dname = seen_nsec = @@ -4275,7 +5099,8 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node, seen_nsec = ISC_TRUE; else if (rdataset.type == dns_rdatatype_nsec3) seen_nsec3 = ISC_TRUE; - seen_rr = ISC_TRUE; + if (rdataset.type != dns_rdatatype_rrsig) + seen_rr = ISC_TRUE; dns_rdataset_disassociate(&rdataset); } if (result != ISC_R_NOMORE) @@ -4299,9 +5124,15 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node, if (build_nsec && !seen_nsec3 && !seen_nsec && seen_rr) { /* Build and add NSEC. */ bottom = (seen_ns && !seen_soa) || seen_dname; - CHECK(add_nsec(db, version, name, node, minimum, bottom, diff)); - /* Count a NSEC generation as a signature generation. */ - (*signatures)--; + /* + * Build a NSEC record except at the origin. + */ + if (!dns_name_equal(name, dns_db_origin(db))) { + CHECK(add_nsec(db, version, name, node, minimum, + bottom, diff)); + /* Count a NSEC generation as a signature generation. */ + (*signatures)--; + } } result = dns_rdatasetiter_first(iterator); while (result == ISC_R_SUCCESS) { @@ -4309,7 +5140,10 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node, if (rdataset.type == dns_rdatatype_soa || rdataset.type == dns_rdatatype_rrsig) goto next_rdataset; - if (is_ksk && rdataset.type != dns_rdatatype_dnskey) + if (rdataset.type == dns_rdatatype_dnskey) { + if (!is_ksk && keyset_kskonly) + goto next_rdataset; + } else if (is_ksk) goto next_rdataset; if (*delegation && rdataset.type != dns_rdatatype_ds && @@ -4318,6 +5152,7 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node, if (signed_with_key(db, node, version, rdataset.type, key)) goto next_rdataset; /* Calculate the signature, creating a RRSIG RDATA. */ + isc_buffer_clear(&buffer); CHECK(dns_dnssec_sign(name, &rdataset, key, &inception, &expire, mctx, &buffer, &rdata)); /* Update the database and journal with the RRSIG. */ @@ -4334,7 +5169,7 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node, result = ISC_R_SUCCESS; if (seen_dname) *delegation = ISC_TRUE; -failure: + failure: if (dns_rdataset_isassociated(&rdataset)) dns_rdataset_disassociate(&rdataset); if (iterator != NULL) @@ -4342,63 +5177,45 @@ failure: return (result); } +/* + * If 'update_only' is set then don't create a NSEC RRset if it doesn't exist. + */ static isc_result_t updatesecure(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, - dns_ttl_t minimum, isc_boolean_t *secureupdated, dns_diff_t *diff) + dns_ttl_t minimum, isc_boolean_t update_only, dns_diff_t *diff) { isc_result_t result; - dns_rdata_t rdata = DNS_RDATA_INIT; - unsigned char nsecbuffer[DNS_NSEC_BUFFERSIZE]; dns_rdataset_t rdataset; - dns_rdata_nsec_t nsec; dns_dbnode_t *node = NULL; - /* - * Check to see if the OPT bit has already been cleared. - */ CHECK(dns_db_getoriginnode(db, &node)); - dns_rdataset_init(&rdataset); - CHECK(dns_db_findrdataset(db, node, version, dns_rdatatype_nsec, - dns_rdatatype_none, 0, &rdataset, NULL)); - CHECK(dns_rdataset_first(&rdataset)); - dns_rdataset_current(&rdataset, &rdata); - - /* - * Find the NEXT name for building the new record. - */ - CHECK(dns_rdata_tostruct(&rdata, &nsec, NULL)); - - /* - * Delete the old NSEC record. - */ - CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_DEL, name, minimum, - &rdata)); - dns_rdata_reset(&rdata); - - /* - * Add the new NSEC record. - */ - CHECK(dns_nsec_buildrdata(db, version, node, &nsec.next, nsecbuffer, - &rdata)); - CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name, minimum, - &rdata)); - dns_rdata_reset(&rdata); - - if (secureupdated != NULL) - *secureupdated = ISC_TRUE; - + if (update_only) { + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec, + dns_rdatatype_none, + 0, &rdataset, NULL); + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (result == ISC_R_NOTFOUND) + goto success; + if (result != ISC_R_SUCCESS) + goto failure; + } + CHECK(delete_nsec(db, version, node, name, diff)); + CHECK(add_nsec(db, version, name, node, minimum, ISC_FALSE, diff)); + success: + result = ISC_R_SUCCESS; failure: if (node != NULL) dns_db_detachnode(db, &node); - if (dns_rdataset_isassociated(&rdataset)) - dns_rdataset_disassociate(&rdataset); return (result); } static isc_result_t -updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version, - dns_name_t *name, dns_rdatatype_t privatetype, - dns_diff_t *diff) +updatesignwithkey(dns_zone_t *zone, dns_signing_t *signing, + dns_dbversion_t *version, isc_boolean_t build_nsec3, + dns_ttl_t minimum, dns_diff_t *diff) { isc_result_t result; dns_dbnode_t *node = NULL; @@ -4406,43 +5223,68 @@ updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version, dns_rdata_t rdata = DNS_RDATA_INIT; unsigned char data[5]; isc_boolean_t seen_done = ISC_FALSE; + isc_boolean_t have_rr = ISC_FALSE; dns_rdataset_init(&rdataset); result = dns_db_getoriginnode(signing->db, &node); if (result != ISC_R_SUCCESS) goto failure; - result = dns_db_findrdataset(signing->db, node, version, privatetype, - dns_rdatatype_none, 0, &rdataset, NULL); + result = dns_db_findrdataset(signing->db, node, version, + zone->privatetype, dns_rdatatype_none, + 0, &rdataset, NULL); if (result == ISC_R_NOTFOUND) { + INSIST(!dns_rdataset_isassociated(&rdataset)); result = ISC_R_SUCCESS; goto failure; } - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + INSIST(!dns_rdataset_isassociated(&rdataset)); goto failure; + } for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(&rdataset)) { dns_rdataset_current(&rdataset, &rdata); + /* + * If we don't match the algorithm or keyid skip the record. + */ if (rdata.length != 5 || rdata.data[0] != signing->algorithm || rdata.data[1] != ((signing->keyid >> 8) & 0xff) || rdata.data[2] != (signing->keyid & 0xff)) { + have_rr = ISC_TRUE; dns_rdata_reset(&rdata); continue; } - if (!signing->delete && rdata.data[4] != 0) + /* + * We have a match. If we were signing (!signing->delete) + * and we already have a record indicating that we have + * finished signing (rdata.data[4] != 0) then keep it. + * Otherwise it needs to be deleted as we have removed all + * the signatures (signing->delete), so any record indicating + * completion is now out of date, or we have finished signing + * with the new record so we no longer need to remember that + * we need to sign the zone with the matching key across a + * nameserver re-start. + */ + if (!signing->delete && rdata.data[4] != 0) { seen_done = ISC_TRUE; - else + have_rr = ISC_TRUE; + } else CHECK(update_one_rr(signing->db, version, diff, - DNS_DIFFOP_DEL, name, + DNS_DIFFOP_DEL, &zone->origin, rdataset.ttl, &rdata)); dns_rdata_reset(&rdata); } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; if (!signing->delete && !seen_done) { - + /* + * If we were signing then we need to indicate that we have + * finished signing the zone with this key. If it is already + * there we don't need to add it a second time. + */ data[0] = signing->algorithm; data[1] = (signing->keyid >> 8) & 0xff; data[2] = signing->keyid & 0xff; @@ -4450,11 +5292,23 @@ updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version, data[4] = 1; rdata.length = sizeof(data); rdata.data = data; - rdata.type = privatetype; + rdata.type = zone->privatetype; rdata.rdclass = dns_db_class(signing->db); CHECK(update_one_rr(signing->db, version, diff, DNS_DIFFOP_ADD, - name, rdataset.ttl, &rdata)); + &zone->origin, rdataset.ttl, &rdata)); + } else if (!have_rr) { + dns_name_t *origin = dns_db_origin(signing->db); + /* + * Rebuild the NSEC/NSEC3 record for the origin as we no + * longer have any private records. + */ + if (build_nsec3) + CHECK(dns_nsec3_addnsec3s(signing->db, version, origin, + minimum, ISC_FALSE, diff)); + CHECK(updatesecure(signing->db, version, origin, minimum, + ISC_TRUE, diff)); } + failure: if (dns_rdataset_isassociated(&rdataset)) dns_rdataset_disassociate(&rdataset); @@ -4463,9 +5317,15 @@ updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version, return (result); } +/* + * If 'active' is set then we are not done with the chain yet so only + * delete the nsec3param record which indicates a full chain exists + * (flags == 0). + */ static isc_result_t fixup_nsec3param(dns_db_t *db, dns_dbversion_t *ver, dns_nsec3chain_t *chain, - isc_boolean_t active, dns_diff_t *diff) + isc_boolean_t active, dns_rdatatype_t privatetype, + dns_diff_t *diff) { dns_dbnode_t *node = NULL; dns_name_t *name = dns_db_origin(db); @@ -4484,7 +5344,7 @@ fixup_nsec3param(dns_db_t *db, dns_dbversion_t *ver, dns_nsec3chain_t *chain, result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, 0, 0, &rdataset, NULL); if (result == ISC_R_NOTFOUND) - goto add; + goto try_private; if (result != ISC_R_SUCCESS) goto failure; @@ -4520,6 +5380,50 @@ fixup_nsec3param(dns_db_t *db, dns_dbversion_t *ver, dns_nsec3chain_t *chain, if (result != ISC_R_NOMORE) goto failure; + dns_rdataset_disassociate(&rdataset); + + try_private: + + if (active) + goto add; + /* + * Delete all private records which match that in nsec3chain. + */ + result = dns_db_findrdataset(db, node, ver, privatetype, + 0, 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) + goto add; + if (result != ISC_R_SUCCESS) + goto failure; + + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t private = DNS_RDATA_INIT; + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + + dns_rdataset_current(&rdataset, &private); + if (!dns_nsec3param_fromprivate(&private, &rdata, + buf, sizeof(buf))) + continue; + CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); + + if (nsec3param.hash != chain->nsec3param.hash || + nsec3param.iterations != chain->nsec3param.iterations || + nsec3param.salt_length != chain->nsec3param.salt_length || + memcmp(nsec3param.salt, chain->nsec3param.salt, + nsec3param.salt_length)) { + dns_rdata_reset(&rdata); + continue; + } + + CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, + name, rdataset.ttl, &private)); + dns_rdata_reset(&rdata); + } + if (result != ISC_R_NOMORE) + goto failure; + add: if ((chain->nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) { result = ISC_R_SUCCESS; @@ -4620,7 +5524,7 @@ deletematchingnsec3(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node, static isc_result_t need_nsec_chain(dns_db_t *db, dns_dbversion_t *ver, const dns_rdata_nsec3param_t *param, - isc_boolean_t *answer, isc_boolean_t *updatensec) + isc_boolean_t *answer) { dns_dbnode_t *node = NULL; dns_rdata_t rdata = DNS_RDATA_INIT; @@ -4634,29 +5538,19 @@ need_nsec_chain(dns_db_t *db, dns_dbversion_t *ver, RUNTIME_CHECK(result == ISC_R_SUCCESS); dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, 0, 0, &rdataset, NULL); - if (result == ISC_R_NOTFOUND) - goto check_nsec3param; - - if (result != ISC_R_SUCCESS) - goto failure; - - CHECK(dns_rdataset_first(&rdataset)); - dns_rdataset_current(&rdataset, &rdata); - - if (!dns_nsec_typepresent(&rdata, dns_rdatatype_opt)) { - /* - * We have a complete NSEC chain. Signal to update - * the apex NSEC record. - */ - *updatensec = ISC_TRUE; - goto failure; + if (result == ISC_R_SUCCESS) { + dns_rdataset_disassociate(&rdataset); + dns_db_detachnode(db, &node); + return (result); + } + if (result != ISC_R_NOTFOUND) { + dns_db_detachnode(db, &node); + return (result); } - dns_rdataset_disassociate(&rdataset); - dns_rdata_reset(&rdata); - check_nsec3param: result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, 0, 0, &rdataset, NULL); if (result == ISC_R_NOTFOUND) { @@ -4705,13 +5599,60 @@ need_nsec_chain(dns_db_t *db, dns_dbversion_t *ver, return (result); } +static isc_result_t +update_sigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version, + dst_key_t *zone_keys[], unsigned int nkeys, dns_zone_t *zone, + isc_stdtime_t inception, isc_stdtime_t expire, isc_stdtime_t now, + isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly, + dns_diff_t *sig_diff) +{ + dns_difftuple_t *tuple; + isc_result_t result; + + for (tuple = ISC_LIST_HEAD(diff->tuples); + tuple != NULL; + tuple = ISC_LIST_HEAD(diff->tuples)) { + result = del_sigs(zone, db, version, &tuple->name, + tuple->rdata.type, sig_diff, + zone_keys, nkeys, now); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "update_sigs:del_sigs -> %s\n", + dns_result_totext(result)); + return (result); + } + result = add_sigs(db, version, &tuple->name, + tuple->rdata.type, sig_diff, + zone_keys, nkeys, zone->mctx, inception, + expire, check_ksk, keyset_kskonly); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "update_sigs:add_sigs -> %s\n", + dns_result_totext(result)); + return (result); + } + + do { + dns_difftuple_t *next = ISC_LIST_NEXT(tuple, link); + while (next != NULL && + (tuple->rdata.type != next->rdata.type || + !dns_name_equal(&tuple->name, &next->name))) + next = ISC_LIST_NEXT(next, link); + ISC_LIST_UNLINK(diff->tuples, tuple, link); + dns_diff_appendminimal(sig_diff, &tuple); + INSIST(tuple == NULL); + tuple = next; + } while (tuple != NULL); + } + return (ISC_R_SUCCESS); +} + /* * Incrementally build and sign a new NSEC3 chain using the parameters * requested. */ static void zone_nsec3chain(dns_zone_t *zone) { - const char *journalfile; dns_db_t *db = NULL; dns_dbnode_t *node = NULL; dns_dbversion_t *version = NULL; @@ -4727,7 +5668,7 @@ zone_nsec3chain(dns_zone_t *zone) { dns_nsec3chainlist_t cleanup; dst_key_t *zone_keys[MAXZONEKEYS]; isc_int32_t signatures; - isc_boolean_t check_ksk, is_ksk; + isc_boolean_t check_ksk, keyset_kskonly, is_ksk; isc_boolean_t delegation; isc_boolean_t first; isc_result_t result; @@ -4740,9 +5681,9 @@ zone_nsec3chain(dns_zone_t *zone) { isc_boolean_t seen_soa, seen_ns, seen_dname, seen_ds; isc_boolean_t seen_nsec, seen_nsec3, seen_rr; dns_rdatasetiter_t *iterator = NULL; - dns_difftuple_t *tuple; isc_boolean_t buildnsecchain; isc_boolean_t updatensec = ISC_FALSE; + dns_rdatatype_t privatetype = zone->privatetype; dns_rdataset_init(&rdataset); dns_fixedname_init(&fixed); @@ -4799,8 +5740,7 @@ zone_nsec3chain(dns_zone_t *zone) { stop = now + 5; check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); - if (check_ksk) - check_ksk = ksk_sanity(db, version); + keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY); /* * We keep pulling nodes off each iterator in turn until @@ -4924,9 +5864,17 @@ zone_nsec3chain(dns_zone_t *zone) { * Process one node. */ dns_dbiterator_pause(nsec3chain->dbiterator); - CHECK(dns_nsec3_addnsec3(db, version, name, - &nsec3chain->nsec3param, - zone->minimum, unsecure, &nsec3_diff)); + result = dns_nsec3_addnsec3(db, version, name, + &nsec3chain->nsec3param, + zone->minimum, unsecure, + &nsec3_diff); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" + "dns_nsec3_addnsec3 -> %s\n", + dns_result_totext(result)); + goto failure; + } + /* * Treat each call to dns_nsec3_addnsec3() as if it's cost is * two signatures. Additionally there will, in general, be @@ -4948,7 +5896,8 @@ zone_nsec3chain(dns_zone_t *zone) { if (result == ISC_R_NOMORE && nsec3chain->delete_nsec) { CHECK(fixup_nsec3param(db, version, nsec3chain, - ISC_FALSE, ¶m_diff)); + ISC_FALSE, privatetype, + ¶m_diff)); LOCK_ZONE(zone); ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, link); @@ -4962,12 +5911,14 @@ zone_nsec3chain(dns_zone_t *zone) { CHECK(fixup_nsec3param(db, version, nsec3chain, ISC_TRUE, + privatetype, ¶m_diff)); nsec3chain->delete_nsec = ISC_TRUE; goto same_addchain; } CHECK(fixup_nsec3param(db, version, nsec3chain, - ISC_FALSE, ¶m_diff)); + ISC_FALSE, privatetype, + ¶m_diff)); LOCK_ZONE(zone); ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, link); @@ -5028,10 +5979,22 @@ zone_nsec3chain(dns_zone_t *zone) { * of removing this NSEC3 chain. */ if (first && !updatensec && - (nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_NONSEC) == 0) - CHECK(need_nsec_chain(db, version, - &nsec3chain->nsec3param, - &buildnsecchain, &updatensec)); + (nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_NONSEC) == 0) { + result = need_nsec_chain(db, version, + &nsec3chain->nsec3param, + &buildnsecchain); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:" + "need_nsec_chain -> %s\n", + dns_result_totext(result)); + goto failure; + } + } + + if (first) + dns_zone_log(zone, ISC_LOG_DEBUG(3), "zone_nsec3chain:" + "buildnsecchain = %u\n", buildnsecchain); dns_dbiterator_current(nsec3chain->dbiterator, &node, name); delegation = ISC_FALSE; @@ -5040,16 +6003,33 @@ zone_nsec3chain(dns_zone_t *zone) { /* * Delete the NSECPARAM record that matches this chain. */ - if (first) - CHECK(fixup_nsec3param(db, version, nsec3chain, - ISC_TRUE, ¶m_diff)); + if (first) { + result = fixup_nsec3param(db, version, + nsec3chain, + ISC_TRUE, privatetype, + ¶m_diff); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:" + "fixup_nsec3param -> %s\n", + dns_result_totext(result)); + goto failure; + } + } /* * Delete the NSEC3 records. */ - CHECK(deletematchingnsec3(db, version, node, name, - &nsec3chain->nsec3param, - &nsec3_diff)); + result = deletematchingnsec3(db, version, node, name, + &nsec3chain->nsec3param, + &nsec3_diff); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:" + "deletematchingnsec3 -> %s\n", + dns_result_totext(result)); + goto failure; + } goto next_removenode; } @@ -5100,7 +6080,8 @@ zone_nsec3chain(dns_zone_t *zone) { seen_nsec = ISC_TRUE; else if (rdataset.type == dns_rdatatype_nsec3) seen_nsec3 = ISC_TRUE; - seen_rr = ISC_TRUE; + if (rdataset.type != dns_rdatatype_rrsig) + seen_rr = ISC_TRUE; dns_rdataset_disassociate(&rdataset); } dns_rdatasetiter_destroy(&iterator); @@ -5110,8 +6091,14 @@ zone_nsec3chain(dns_zone_t *zone) { if ((seen_ns && !seen_soa) || seen_dname) delegation = ISC_TRUE; - CHECK(add_nsec(db, version, name, node, zone->minimum, - delegation, &nsec_diff)); + /* + * Add a NSEC record except at the origin. + */ + if (!dns_name_equal(name, dns_db_origin(db))) { + dns_dbiterator_pause(nsec3chain->dbiterator); + CHECK(add_nsec(db, version, name, node, zone->minimum, + delegation, &nsec_diff)); + } next_removenode: first = ISC_FALSE; @@ -5133,8 +6120,17 @@ zone_nsec3chain(dns_zone_t *zone) { UNLOCK_ZONE(zone); ISC_LIST_APPEND(cleanup, nsec3chain, link); dns_dbiterator_pause(nsec3chain->dbiterator); - CHECK(fixup_nsec3param(db, version, nsec3chain, - ISC_FALSE, ¶m_diff)); + result = fixup_nsec3param(db, version, + nsec3chain, ISC_FALSE, + privatetype, + ¶m_diff); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:" + "fixup_nsec3param -> %s\n", + dns_result_totext(result)); + goto failure; + } goto next_removechain; } else if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, @@ -5166,107 +6162,101 @@ zone_nsec3chain(dns_zone_t *zone) { } /* - * Add / update signatures for the NSEC3 records. + * We may need to update the NSEC/NSEC3 records for the zone apex. */ - for (tuple = ISC_LIST_HEAD(nsec3_diff.tuples); - tuple != NULL; - tuple = ISC_LIST_HEAD(nsec3_diff.tuples)) { - /* - * We have changed the NSEC3 RRset above so we need to update - * the signatures. - */ - result = del_sigs(zone, db, version, &tuple->name, - dns_rdatatype_nsec3, &sig_diff, - zone_keys, nkeys, now); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_nsec3chain:del_sigs -> %s\n", - dns_result_totext(result)); - goto failure; - } - result = add_sigs(db, version, &tuple->name, - dns_rdatatype_nsec3, &sig_diff, zone_keys, - nkeys, zone->mctx, inception, expire, - check_ksk); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_nsec3chain:add_sigs -> %s\n", - dns_result_totext(result)); - goto failure; + if (!ISC_LIST_EMPTY(param_diff.tuples)) { + isc_boolean_t rebuild_nsec = ISC_FALSE, + rebuild_nsec3 = ISC_FALSE; + result = dns_db_getoriginnode(db, &node); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + result = dns_db_allrdatasets(db, node, version, 0, &iterator); + for (result = dns_rdatasetiter_first(iterator); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(iterator)) { + dns_rdatasetiter_current(iterator, &rdataset); + if (rdataset.type == dns_rdatatype_nsec) + rebuild_nsec = ISC_TRUE; + if (rdataset.type == dns_rdatatype_nsec3param) + rebuild_nsec3 = ISC_TRUE; + dns_rdataset_disassociate(&rdataset); } + dns_rdatasetiter_destroy(&iterator); + dns_db_detachnode(db, &node); - do { - dns_difftuple_t *next = ISC_LIST_NEXT(tuple, link); - while (next != NULL && - !dns_name_equal(&tuple->name, &next->name)) - next = ISC_LIST_NEXT(next, link); - ISC_LIST_UNLINK(nsec3_diff.tuples, tuple, link); - dns_diff_appendminimal(&sig_diff, &tuple); - INSIST(tuple == NULL); - tuple = next; - } while (tuple != NULL); - } - - for (tuple = ISC_LIST_HEAD(param_diff.tuples); - tuple != NULL; - tuple = ISC_LIST_HEAD(param_diff.tuples)) { - /* - * We have changed the NSEC3PARAM RRset above so we need to - * update the signatures. - */ - result = del_sigs(zone, db, version, &tuple->name, - dns_rdatatype_nsec3param, &sig_diff, - zone_keys, nkeys, now); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_nsec3chain:del_sigs -> %s\n", - dns_result_totext(result)); - goto failure; + if (rebuild_nsec) { + if (nsec3chain != NULL) + dns_dbiterator_pause(nsec3chain->dbiterator); + result = updatesecure(db, version, &zone->origin, + zone->minimum, ISC_TRUE, + &nsec_diff); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:" + "updatesecure -> %s\n", + dns_result_totext(result)); + goto failure; + } } - result = add_sigs(db, version, &tuple->name, - dns_rdatatype_nsec3param, &sig_diff, - zone_keys, nkeys, zone->mctx, inception, - expire, check_ksk); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_nsec3chain:add_sigs -> %s\n", - dns_result_totext(result)); - goto failure; + if (rebuild_nsec3) { + result = dns_nsec3_addnsec3s(db, version, + dns_db_origin(db), + zone->minimum, ISC_FALSE, + &nsec3_diff); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_nsec3chain:" + "dns_nsec3_addnsec3s -> %s\n", + dns_result_totext(result)); + goto failure; + } } - ISC_LIST_UNLINK(param_diff.tuples, tuple, link); - dns_diff_appendminimal(&sig_diff, &tuple); - INSIST(tuple == NULL); } - if (updatensec) - CHECK(updatesecure(db, version, &zone->origin, zone->minimum, - NULL, &nsec_diff)); + /* + * Add / update signatures for the NSEC3 records. + */ + result = update_sigs(&nsec3_diff, db, version, zone_keys, + nkeys, zone, inception, expire, now, + check_ksk, keyset_kskonly, &sig_diff); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" + "update_sigs -> %s\n", dns_result_totext(result)); + goto failure; + } - for (tuple = ISC_LIST_HEAD(nsec_diff.tuples); - tuple != NULL; - tuple = ISC_LIST_HEAD(nsec_diff.tuples)) { - result = del_sigs(zone, db, version, &tuple->name, - dns_rdatatype_nsec, &sig_diff, - zone_keys, nkeys, now); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_nsec3chain:del_sigs -> %s\n", - dns_result_totext(result)); - goto failure; - } - result = add_sigs(db, version, &tuple->name, - dns_rdatatype_nsec, &sig_diff, - zone_keys, nkeys, zone->mctx, inception, - expire, check_ksk); + /* + * We have changed the NSEC3PARAM or private RRsets + * above so we need to update the signatures. + */ + result = update_sigs(¶m_diff, db, version, zone_keys, + nkeys, zone, inception, expire, now, + check_ksk, keyset_kskonly, &sig_diff); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" + "update_sigs -> %s\n", dns_result_totext(result)); + goto failure; + } + + if (updatensec) { + if (nsec3chain != NULL) + dns_dbiterator_pause(nsec3chain->dbiterator); + result = updatesecure(db, version, &zone->origin, + zone->minimum, ISC_FALSE, &nsec_diff); if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_nsec3chain:add_sigs -> %s\n", + dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" + "updatesecure -> %s\n", dns_result_totext(result)); goto failure; } - ISC_LIST_UNLINK(nsec_diff.tuples, tuple, link); - dns_diff_appendminimal(&sig_diff, &tuple); - INSIST(tuple == NULL); + } + + result = update_sigs(&nsec_diff, db, version, zone_keys, + nkeys, zone, inception, expire, now, + check_ksk, keyset_kskonly, &sig_diff); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" + "update_sigs -> %s\n", dns_result_totext(result)); + goto failure; } /* @@ -5288,41 +6278,22 @@ zone_nsec3chain(dns_zone_t *zone) { if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" "increment_soa_serial -> %s\n", - dns_result_totext(result)); - goto failure; - } - - result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa, - &sig_diff, zone_keys, nkeys, zone->mctx, inception, - soaexpire, check_ksk); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" - "add_sigs -> %s\n", dns_result_totext(result)); - goto failure; - } - - journalfile = dns_zone_getjournal(zone); - if (journalfile != NULL) { - dns_journal_t *journal = NULL; - result = dns_journal_open(zone->mctx, journalfile, - ISC_TRUE, &journal); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" - "dns_journal_open -> %s\n", - dns_result_totext(result)); - goto failure; - } + dns_result_totext(result)); + goto failure; + } - result = dns_journal_write_transaction(journal, &sig_diff); - dns_journal_destroy(&journal); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" - "dns_journal_write_transaction -> %s\n", - dns_result_totext(result)); - goto failure; - } + result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa, + &sig_diff, zone_keys, nkeys, zone->mctx, inception, + soaexpire, check_ksk, keyset_kskonly); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" + "add_sigs -> %s\n", dns_result_totext(result)); + goto failure; } + /* Write changes to journal file. */ + zone_journal(zone, &sig_diff, "zone_nsec3chain"); + LOCK_ZONE(zone); zone_needdump(zone, DNS_DUMP_DELAY); UNLOCK_ZONE(zone); @@ -5358,6 +6329,9 @@ zone_nsec3chain(dns_zone_t *zone) { set_resigntime(zone); failure: + if (result != ISC_R_SUCCESS) + dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain: %s\n", + dns_result_totext(result)); /* * On error roll back the current nsec3chain. */ @@ -5414,6 +6388,8 @@ zone_nsec3chain(dns_zone_t *zone) { for (i = 0; i < nkeys; i++) dst_key_free(&zone_keys[i]); + if (node != NULL) + dns_db_detachnode(db, &node); if (version != NULL) { dns_db_closeversion(db, &version, ISC_FALSE); dns_db_detach(&db); @@ -5506,11 +6482,11 @@ del_sig(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, */ static void zone_sign(dns_zone_t *zone) { - const char *journalfile; dns_db_t *db = NULL; dns_dbnode_t *node = NULL; dns_dbversion_t *version = NULL; dns_diff_t sig_diff; + dns_diff_t post_diff; dns_fixedname_t fixed; dns_fixedname_t nextfixed; dns_name_t *name, *nextname; @@ -5519,19 +6495,19 @@ zone_sign(dns_zone_t *zone) { dns_signinglist_t cleanup; dst_key_t *zone_keys[MAXZONEKEYS]; isc_int32_t signatures; - isc_boolean_t check_ksk, is_ksk; + isc_boolean_t check_ksk, keyset_kskonly, is_ksk; isc_boolean_t commit = ISC_FALSE; isc_boolean_t delegation; - isc_boolean_t finishedakey = ISC_FALSE; - isc_boolean_t secureupdated = ISC_FALSE; - isc_boolean_t build_nsec3 = ISC_FALSE, build_nsec = ISC_FALSE; + isc_boolean_t build_nsec = ISC_FALSE; + isc_boolean_t build_nsec3 = ISC_FALSE; isc_boolean_t first; isc_result_t result; isc_stdtime_t now, inception, soaexpire, expire, stop; isc_uint32_t jitter; - unsigned int i; + unsigned int i, j; unsigned int nkeys = 0; isc_uint32_t nodes; + isc_boolean_t was_ksk; dns_rdataset_init(&rdataset); dns_fixedname_init(&fixed); @@ -5540,6 +6516,7 @@ zone_sign(dns_zone_t *zone) { nextname = dns_fixedname_name(&nextfixed); dns_diff_init(zone->mctx, &sig_diff); sig_diff.resign = zone->sigresigninginterval; + dns_diff_init(zone->mctx, &post_diff); ISC_LIST_INIT(cleanup); /* @@ -5584,10 +6561,6 @@ zone_sign(dns_zone_t *zone) { expire = soaexpire - jitter % 3600; stop = now + 5; - check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); - if (check_ksk) - check_ksk = ksk_sanity(db, version); - /* * We keep pulling nodes off each iterator in turn until * we have no more nodes to pull off or we reach the limits @@ -5597,39 +6570,17 @@ zone_sign(dns_zone_t *zone) { signatures = zone->signatures; signing = ISC_LIST_HEAD(zone->signing); first = ISC_TRUE; - /* - * See if we have a NSEC chain. - */ - result = dns_db_getoriginnode(db, &node); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - result = dns_db_findrdataset(db, node, version, dns_rdatatype_nsec, - dns_rdatatype_none, 0, &rdataset, NULL); - dns_db_detachnode(db, &node); - if (result == ISC_R_SUCCESS) { + + check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); + keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY); + + /* Determine which type of chain to build */ + CHECK(dns_private_chains(db, version, zone->privatetype, + &build_nsec, &build_nsec3)); + + /* If neither chain is found, default to NSEC */ + if (!build_nsec && !build_nsec3) build_nsec = ISC_TRUE; - dns_rdataset_disassociate(&rdataset); - } else if (result != ISC_R_NOTFOUND) { - goto failure; - } else { - /* - * No NSEC chain present. - * See if we need to build a NSEC3 chain? - */ - result = dns_nsec3_active(db, version, ISC_TRUE, &build_nsec3); - if (result == ISC_R_SUCCESS) { - if (build_nsec3) - build_nsec3 = ISC_FALSE; - else { - result = dns_nsec3_active(db, version, - ISC_FALSE, - &build_nsec3); - if (build_nsec3) - secureupdated = ISC_TRUE; - else - build_nsec = ISC_TRUE; - } - } - } while (signing != NULL && nodes-- > 0 && signatures > 0) { nextsigning = ISC_LIST_NEXT(signing, link); @@ -5637,7 +6588,7 @@ zone_sign(dns_zone_t *zone) { ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); if (signing->done || signing->db != zone->db) { /* - * The zone has been reloaded. We will have + * The zone has been reloaded. We will have * created new signings as part of the reload * process so we can destroy this one. */ @@ -5651,9 +6602,31 @@ zone_sign(dns_zone_t *zone) { if (signing->db != db) goto next_signing; - is_ksk = ISC_FALSE; delegation = ISC_FALSE; + was_ksk = ISC_FALSE; + + if (first && signing->delete) { + /* + * Remove the key we are deleting from consideration. + */ + for (i = 0, j = 0; i < nkeys; i++) { + /* + * Find the key we want to remove. + */ + if (ALG(zone_keys[i]) == signing->algorithm && + dst_key_id(zone_keys[i]) == signing->keyid) + { + if (KSK(zone_keys[i])) + dst_key_free(&zone_keys[i]); + continue; + } + zone_keys[j] = zone_keys[i]; + j++; + } + nkeys = j; + } + dns_dbiterator_current(signing->dbiterator, &node, name); if (signing->delete) { @@ -5661,8 +6634,8 @@ zone_sign(dns_zone_t *zone) { CHECK(del_sig(db, version, name, node, nkeys, signing->algorithm, signing->keyid, &sig_diff)); - goto next_node; } + /* * On the first pass we need to check if the current node * has not been obscured. @@ -5694,26 +6667,77 @@ zone_sign(dns_zone_t *zone) { */ dns_dbiterator_pause(signing->dbiterator); for (i = 0; i < nkeys; i++) { + isc_boolean_t both = ISC_FALSE; + + /* + * Find the keys we want to sign with. + */ + if (!dst_key_isprivate(zone_keys[i])) + continue; + + /* + * When adding look for the specific key. + */ + if (!signing->delete && + (dst_key_alg(zone_keys[i]) != signing->algorithm || + dst_key_id(zone_keys[i]) != signing->keyid)) + continue; + /* - * Find the key we want to sign with. + * When deleting make sure we are properly signed + * with the algorithm that was being removed. */ - if (dst_key_alg(zone_keys[i]) != signing->algorithm || - dst_key_id(zone_keys[i]) != signing->keyid || - !dst_key_isprivate(zone_keys[i])) + if (signing->delete && + ALG(zone_keys[i]) != signing->algorithm) continue; + /* * Do we do KSK processing? */ - if (check_ksk && - (dst_key_flags(zone_keys[i]) & DNS_KEYFLAG_KSK) != 0) - is_ksk = ISC_TRUE; + if (check_ksk && !REVOKE(zone_keys[i])) { + isc_boolean_t have_ksk, have_nonksk; + if (KSK(zone_keys[i])) { + have_ksk = ISC_TRUE; + have_nonksk = ISC_FALSE; + } else { + have_ksk = ISC_FALSE; + have_nonksk = ISC_TRUE; + } + for (j = 0; j < nkeys; j++) { + if (j == i || + ALG(zone_keys[i]) != + ALG(zone_keys[j])) + continue; + if (REVOKE(zone_keys[j])) + continue; + if (KSK(zone_keys[j])) + have_ksk = ISC_TRUE; + else + have_nonksk = ISC_TRUE; + both = have_ksk && have_nonksk; + if (both) + break; + } + } + if (both || REVOKE(zone_keys[i])) + is_ksk = KSK(zone_keys[i]); + else + is_ksk = ISC_FALSE; + CHECK(sign_a_node(db, name, node, version, build_nsec3, build_nsec, zone_keys[i], inception, expire, zone->minimum, is_ksk, - &delegation, &sig_diff, &signatures, - zone->mctx)); - break; + ISC_TF(both && keyset_kskonly), + &delegation, &sig_diff, + &signatures, zone->mctx)); + /* + * If we are adding we are done. Look for other keys + * of the same algorithm if deleting. + */ + if (!signing->delete) + break; } + /* * Go onto next node. */ @@ -5726,9 +6750,7 @@ zone_sign(dns_zone_t *zone) { ISC_LIST_UNLINK(zone->signing, signing, link); ISC_LIST_APPEND(cleanup, signing, link); dns_dbiterator_pause(signing->dbiterator); - finishedakey = ISC_TRUE; - if (!is_ksk && !secureupdated && nkeys != 0 && - build_nsec) { + if (nkeys != 0 && build_nsec) { /* * We have finished regenerating the * zone with a zone signing key. @@ -5740,8 +6762,8 @@ zone_sign(dns_zone_t *zone) { result = updatesecure(db, version, &zone->origin, zone->minimum, - &secureupdated, - &sig_diff); + ISC_FALSE, + &post_diff); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, @@ -5750,16 +6772,19 @@ zone_sign(dns_zone_t *zone) { goto failure; } } - result = updatesignwithkey(signing, version, - &zone->origin, - zone->privatetype, - &sig_diff); + result = updatesignwithkey(zone, signing, + version, + build_nsec3, + zone->minimum, + &post_diff); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, - "updatesignwithkey -> %s\n", + "updatesignwithkey " + "-> %s\n", dns_result_totext(result)); goto failure; } + build_nsec = ISC_FALSE; goto next_signing; } else if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, @@ -5777,205 +6802,979 @@ zone_sign(dns_zone_t *zone) { } while (1); continue; - next_signing: - dns_dbiterator_pause(signing->dbiterator); - signing = nextsigning; - first = ISC_TRUE; - } + next_signing: + dns_dbiterator_pause(signing->dbiterator); + signing = nextsigning; + first = ISC_TRUE; + } + + if (ISC_LIST_HEAD(post_diff.tuples) != NULL) { + result = update_sigs(&post_diff, db, version, zone_keys, + nkeys, zone, inception, expire, now, + check_ksk, keyset_kskonly, &sig_diff); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, "zone_sign:" + "update_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + } + + /* + * Have we changed anything? + */ + if (ISC_LIST_HEAD(sig_diff.tuples) == NULL) { + result = ISC_R_SUCCESS; + goto pauseall; + } + + commit = ISC_TRUE; + + result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa, + &sig_diff, zone_keys, nkeys, now); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_sign:del_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + + result = increment_soa_serial(db, version, &sig_diff, zone->mctx); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_sign:increment_soa_serial -> %s\n", + dns_result_totext(result)); + goto failure; + } + + /* + * Generate maximum life time signatures so that the above loop + * termination is sensible. + */ + result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa, + &sig_diff, zone_keys, nkeys, zone->mctx, inception, + soaexpire, check_ksk, keyset_kskonly); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_sign:add_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + + /* + * Write changes to journal file. + */ + result = zone_journal(zone, &sig_diff, "zone_sign"); + if (result != ISC_R_SUCCESS) + goto failure; + + pauseall: + /* + * Pause all iterators so that dns_db_closeversion() can succeed. + */ + for (signing = ISC_LIST_HEAD(zone->signing); + signing != NULL; + signing = ISC_LIST_NEXT(signing, link)) + dns_dbiterator_pause(signing->dbiterator); + + for (signing = ISC_LIST_HEAD(cleanup); + signing != NULL; + signing = ISC_LIST_NEXT(signing, link)) + dns_dbiterator_pause(signing->dbiterator); + + /* + * Everything has succeeded. Commit the changes. + */ + dns_db_closeversion(db, &version, commit); + + /* + * Everything succeeded so we can clean these up now. + */ + signing = ISC_LIST_HEAD(cleanup); + while (signing != NULL) { + ISC_LIST_UNLINK(cleanup, signing, link); + dns_db_detach(&signing->db); + dns_dbiterator_destroy(&signing->dbiterator); + isc_mem_put(zone->mctx, signing, sizeof *signing); + signing = ISC_LIST_HEAD(cleanup); + } + + set_resigntime(zone); + + if (commit) { + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); + zone_needdump(zone, DNS_DUMP_DELAY); + UNLOCK_ZONE(zone); + } + + failure: + /* + * Rollback the cleanup list. + */ + signing = ISC_LIST_HEAD(cleanup); + while (signing != NULL) { + ISC_LIST_UNLINK(cleanup, signing, link); + ISC_LIST_PREPEND(zone->signing, signing, link); + dns_dbiterator_first(signing->dbiterator); + dns_dbiterator_pause(signing->dbiterator); + signing = ISC_LIST_HEAD(cleanup); + } + + for (signing = ISC_LIST_HEAD(zone->signing); + signing != NULL; + signing = ISC_LIST_NEXT(signing, link)) + dns_dbiterator_pause(signing->dbiterator); + + dns_diff_clear(&sig_diff); + + for (i = 0; i < nkeys; i++) + dst_key_free(&zone_keys[i]); + + if (node != NULL) + dns_db_detachnode(db, &node); + + if (version != NULL) { + dns_db_closeversion(db, &version, ISC_FALSE); + dns_db_detach(&db); + } else if (db != NULL) + dns_db_detach(&db); + + if (ISC_LIST_HEAD(zone->signing) != NULL) { + isc_interval_t i; + if (zone->update_disabled || result != ISC_R_SUCCESS) + isc_interval_set(&i, 60, 0); /* 1 minute */ + else + isc_interval_set(&i, 0, 10000000); /* 10 ms */ + isc_time_nowplusinterval(&zone->signingtime, &i); + } else + isc_time_settoepoch(&zone->signingtime); +} + +static void +normalize_key(dns_rdata_t *rr, dns_rdata_t *target, + unsigned char *data, int size) { + dns_rdata_dnskey_t dnskey; + dns_rdata_keydata_t keydata; + isc_buffer_t buf; + + dns_rdata_reset(target); + isc_buffer_init(&buf, data, size); + + switch (rr->type) { + case dns_rdatatype_dnskey: + dns_rdata_tostruct(rr, &dnskey, NULL); + dnskey.flags &= ~DNS_KEYFLAG_REVOKE; + dns_rdata_fromstruct(target, rr->rdclass, dns_rdatatype_dnskey, + &dnskey, &buf); + break; + case dns_rdatatype_keydata: + dns_rdata_tostruct(rr, &keydata, NULL); + dns_keydata_todnskey(&keydata, &dnskey, NULL); + dns_rdata_fromstruct(target, rr->rdclass, dns_rdatatype_dnskey, + &dnskey, &buf); + break; + default: + INSIST(0); + } +} + +/* + * 'rdset' contains either a DNSKEY rdataset from the zone apex, or + * a KEYDATA rdataset from the key zone. + * + * 'rr' contains either a DNSKEY record, or a KEYDATA record + * + * After normalizing keys to the same format (DNSKEY, with revoke bit + * cleared), return ISC_TRUE if a key that matches 'rr' is found in + * 'rdset', or ISC_FALSE if not. + */ + +static isc_boolean_t +matchkey(dns_rdataset_t *rdset, dns_rdata_t *rr) { + unsigned char data1[4096], data2[4096]; + dns_rdata_t rdata, rdata1, rdata2; + isc_result_t result; + + dns_rdata_init(&rdata); + dns_rdata_init(&rdata1); + dns_rdata_init(&rdata2); + + normalize_key(rr, &rdata1, data1, sizeof(data1)); + + for (result = dns_rdataset_first(rdset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdset)) { + dns_rdata_reset(&rdata); + dns_rdataset_current(rdset, &rdata); + normalize_key(&rdata, &rdata2, data2, sizeof(data2)); + if (dns_rdata_compare(&rdata1, &rdata2) == 0) + return (ISC_TRUE); + } + + return (ISC_FALSE); +} + +/* + * Calculate the refresh interval for a keydata zone, per + * RFC5011: MAX(1 hr, + * MIN(15 days, + * 1/2 * OrigTTL, + * 1/2 * RRSigExpirationInterval)) + * or for retries: MAX(1 hr, + * MIN(1 day, + * 1/10 * OrigTTL, + * 1/10 * RRSigExpirationInterval)) + */ +static inline isc_stdtime_t +refresh_time(dns_keyfetch_t *kfetch, isc_boolean_t retry) { + isc_result_t result; + isc_uint32_t t; + dns_rdataset_t *rdset; + dns_rdata_t sigrr = DNS_RDATA_INIT; + dns_rdata_sig_t sig; + isc_stdtime_t now; + + isc_stdtime_get(&now); + + if (dns_rdataset_isassociated(&kfetch->dnskeysigset)) + rdset = &kfetch->dnskeysigset; + else + return (now + HOUR); + + result = dns_rdataset_first(rdset); + if (result != ISC_R_SUCCESS) + return (now + HOUR); + + dns_rdataset_current(rdset, &sigrr); + result = dns_rdata_tostruct(&sigrr, &sig, NULL); - if (secureupdated) { - /* - * We have changed the NSEC RRset above so we need to update - * the signatures. - */ - result = del_sigs(zone, db, version, &zone->origin, - dns_rdatatype_nsec, &sig_diff, zone_keys, - nkeys, now); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_sign:del_sigs -> %s\n", - dns_result_totext(result)); - goto failure; + if (!retry) { + t = sig.originalttl / 2; + + if (isc_serial_gt(sig.timeexpire, now)) { + isc_uint32_t exp = (sig.timeexpire - now) / 2; + if (t > exp) + t = exp; } - result = add_sigs(db, version, &zone->origin, - dns_rdatatype_nsec, &sig_diff, zone_keys, - nkeys, zone->mctx, inception, soaexpire, - check_ksk); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_sign:add_sigs -> %s\n", - dns_result_totext(result)); - goto failure; + + if (t > (15*DAY)) + t = (15*DAY); + + if (t < HOUR) + t = HOUR; + } else { + t = sig.originalttl / 10; + + if (isc_serial_gt(sig.timeexpire, now)) { + isc_uint32_t exp = (sig.timeexpire - now) / 10; + if (t > exp) + t = exp; } + + if (t > DAY) + t = DAY; + + if (t < HOUR) + t = HOUR; } - if (finishedakey) { - /* - * We have changed the RRset above so we need to update - * the signatures. - */ - result = del_sigs(zone, db, version, &zone->origin, - zone->privatetype, &sig_diff, - zone_keys, nkeys, now); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_sign:del_sigs -> %s\n", - dns_result_totext(result)); - goto failure; - } - result = add_sigs(db, version, &zone->origin, - zone->privatetype, &sig_diff, - zone_keys, nkeys, zone->mctx, inception, - soaexpire, check_ksk); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_sign:add_sigs -> %s\n", - dns_result_totext(result)); - goto failure; - } + return (now + t); +} + +/* + * This routine is called when no changes are needed in a KEYDATA + * record except to simply update the refresh timer. Caller should + * hold zone lock. + */ +static isc_result_t +minimal_update(dns_keyfetch_t *kfetch, dns_dbversion_t *ver, dns_diff_t *diff) +{ + isc_result_t result; + isc_buffer_t keyb; + unsigned char key_buf[4096]; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_keydata_t keydata; + dns_name_t *name; + dns_zone_t *zone = kfetch->zone; + isc_stdtime_t now; + + name = dns_fixedname_name(&kfetch->name); + isc_stdtime_get(&now); + + for (result = dns_rdataset_first(&kfetch->keydataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&kfetch->keydataset)) { + dns_rdata_reset(&rdata); + dns_rdataset_current(&kfetch->keydataset, &rdata); + + /* Delete old version */ + CHECK(update_one_rr(kfetch->db, ver, diff, DNS_DIFFOP_DEL, + name, 0, &rdata)); + + /* Update refresh timer */ + CHECK(dns_rdata_tostruct(&rdata, &keydata, NULL)); + keydata.refresh = refresh_time(kfetch, ISC_TRUE); + set_refreshkeytimer(zone, &keydata, now); + + dns_rdata_reset(&rdata); + isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); + CHECK(dns_rdata_fromstruct(&rdata, + zone->rdclass, dns_rdatatype_keydata, + &keydata, &keyb)); + + /* Insert updated version */ + CHECK(update_one_rr(kfetch->db, ver, diff, DNS_DIFFOP_ADD, + name, 0, &rdata)); } + result = ISC_R_SUCCESS; + failure: + return (result); +} - /* - * Have we changed anything? - */ - if (ISC_LIST_HEAD(sig_diff.tuples) == NULL) - goto pauseall; +/* + * Verify that DNSKEY set is signed by the key specified in 'keydata'. + */ +static isc_boolean_t +revocable(dns_keyfetch_t *kfetch, dns_rdata_keydata_t *keydata) { + isc_result_t result; + dns_name_t *keyname; + isc_mem_t *mctx; + dns_rdata_t sigrr = DNS_RDATA_INIT; + dns_rdata_t rr = DNS_RDATA_INIT; + dns_rdata_rrsig_t sig; + dns_rdata_dnskey_t dnskey; + dst_key_t *dstkey = NULL; + unsigned char key_buf[4096]; + isc_buffer_t keyb; + isc_boolean_t answer = ISC_FALSE; + + REQUIRE(kfetch != NULL && keydata != NULL); + REQUIRE(dns_rdataset_isassociated(&kfetch->dnskeysigset)); + + keyname = dns_fixedname_name(&kfetch->name); + mctx = kfetch->zone->view->mctx; + + /* Generate a key from keydata */ + isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); + dns_keydata_todnskey(keydata, &dnskey, NULL); + dns_rdata_fromstruct(&rr, keydata->common.rdclass, dns_rdatatype_dnskey, + &dnskey, &keyb); + result = dns_dnssec_keyfromrdata(keyname, &rr, mctx, &dstkey); + if (result != ISC_R_SUCCESS) + return (ISC_FALSE); - commit = ISC_TRUE; + /* See if that key generated any of the signatures */ + for (result = dns_rdataset_first(&kfetch->dnskeysigset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&kfetch->dnskeysigset)) { + dns_fixedname_t fixed; + dns_fixedname_init(&fixed); - result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa, - &sig_diff, zone_keys, nkeys, now); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_sign:del_sigs -> %s\n", - dns_result_totext(result)); - goto failure; + dns_rdata_reset(&sigrr); + dns_rdataset_current(&kfetch->dnskeysigset, &sigrr); + result = dns_rdata_tostruct(&sigrr, &sig, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + if (dst_key_alg(dstkey) == sig.algorithm && + (dst_key_id(dstkey) == sig.keyid || + (sig.algorithm != 1 && sig.keyid == + ((dst_key_id(dstkey) + 128) & 0xffff)))) { + result = dns_dnssec_verify2(keyname, + &kfetch->dnskeyset, + dstkey, ISC_FALSE, mctx, &sigrr, + dns_fixedname_name(&fixed)); + + dns_zone_log(kfetch->zone, ISC_LOG_DEBUG(3), + "Confirm revoked DNSKEY is self-signed: " + "%s", dns_result_totext(result)); + + if (result == ISC_R_SUCCESS) { + answer = ISC_TRUE; + break; + } + } } - result = increment_soa_serial(db, version, &sig_diff, zone->mctx); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_sign:increment_soa_serial -> %s\n", - dns_result_totext(result)); + dst_key_free(&dstkey); + return (answer); +} + +/* + * A DNSKEY set has been fetched from the zone apex of a zone whose trust + * anchors are being managed; scan the keyset, and update the key zone and the + * local trust anchors according to RFC5011. + */ +static void +keyfetch_done(isc_task_t *task, isc_event_t *event) { + isc_result_t result, eresult; + dns_fetchevent_t *devent; + dns_keyfetch_t *kfetch; + dns_zone_t *zone; + isc_mem_t *mctx = NULL; + dns_keytable_t *secroots = NULL; + dns_dbversion_t *ver = NULL; + dns_diff_t diff; + isc_boolean_t changed = ISC_FALSE; + isc_boolean_t alldone = ISC_FALSE; + dns_name_t *keyname; + dns_rdata_t sigrr = DNS_RDATA_INIT; + dns_rdata_t dnskeyrr = DNS_RDATA_INIT; + dns_rdata_t keydatarr = DNS_RDATA_INIT; + dns_rdata_rrsig_t sig; + dns_rdata_dnskey_t dnskey; + dns_rdata_keydata_t keydata; + isc_boolean_t initializing; + char namebuf[DNS_NAME_FORMATSIZE]; + unsigned char key_buf[4096]; + isc_buffer_t keyb; + dst_key_t *dstkey; + isc_stdtime_t now; + int pending = 0; + isc_boolean_t secure; + + UNUSED(task); + INSIST(event != NULL && event->ev_type == DNS_EVENT_FETCHDONE); + INSIST(event->ev_arg != NULL); + + kfetch = event->ev_arg; + zone = kfetch->zone; + isc_mem_attach(zone->mctx, &mctx); + keyname = dns_fixedname_name(&kfetch->name); + + devent = (dns_fetchevent_t *) event; + eresult = devent->result; + + /* Free resources which are not of interest */ + if (devent->node != NULL) + dns_db_detachnode(devent->db, &devent->node); + if (devent->db != NULL) + dns_db_detach(&devent->db); + isc_event_free(&event); + dns_resolver_destroyfetch(&kfetch->fetch); + + isc_stdtime_get(&now); + dns_name_format(keyname, namebuf, sizeof(namebuf)); + + result = dns_view_getsecroots(zone->view, &secroots); + INSIST(result == ISC_R_SUCCESS); + + LOCK_ZONE(zone); + dns_db_newversion(kfetch->db, &ver); + dns_diff_init(mctx, &diff); + + zone->refreshkeycount--; + alldone = ISC_TF(zone->refreshkeycount == 0); + + if (alldone) + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESHING); + + /* Fetch failed */ + if (eresult != ISC_R_SUCCESS || + !dns_rdataset_isassociated(&kfetch->dnskeyset)) { + dns_zone_log(zone, ISC_LOG_WARNING, + "Unable to fetch DNSKEY set " + "'%s': %s", namebuf, dns_result_totext(eresult)); + CHECK(minimal_update(kfetch, ver, &diff)); + changed = ISC_TRUE; goto failure; } - /* - * Generate maximum life time signatures so that the above loop - * termination is sensible. - */ - result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa, - &sig_diff, zone_keys, nkeys, zone->mctx, inception, - soaexpire, check_ksk); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_sign:add_sigs -> %s\n", - dns_result_totext(result)); + /* No RRSIGs found */ + if (!dns_rdataset_isassociated(&kfetch->dnskeysigset)) { + dns_zone_log(zone, ISC_LOG_WARNING, + "No DNSKEY RRSIGs found for " + "'%s': %s", namebuf, dns_result_totext(eresult)); + CHECK(minimal_update(kfetch, ver, &diff)); + changed = ISC_TRUE; goto failure; } /* - * Write changes to journal file. + * Validate the dnskeyset against the current trusted keys. */ - journalfile = dns_zone_getjournal(zone); - if (journalfile != NULL) { - dns_journal_t *journal = NULL; - result = dns_journal_open(zone->mctx, journalfile, - ISC_TRUE, &journal); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_sign:dns_journal_open -> %s\n", - dns_result_totext(result)); - goto failure; - } + for (result = dns_rdataset_first(&kfetch->dnskeysigset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&kfetch->dnskeysigset)) { + dns_keynode_t *keynode = NULL; - result = dns_journal_write_transaction(journal, &sig_diff); - dns_journal_destroy(&journal); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "zone_sign:dns_journal_write_transaction -> %s\n", - dns_result_totext(result)); - goto failure; + dns_rdata_reset(&sigrr); + dns_rdataset_current(&kfetch->dnskeysigset, &sigrr); + result = dns_rdata_tostruct(&sigrr, &sig, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + result = dns_keytable_find(secroots, keyname, &keynode); + while (result == ISC_R_SUCCESS) { + dns_keynode_t *nextnode = NULL; + dns_fixedname_t fixed; + dns_fixedname_init(&fixed); + + dstkey = dns_keynode_key(keynode); + if (dstkey == NULL) /* fail_secure() was called */ + break; + + if (dst_key_alg(dstkey) == sig.algorithm && + dst_key_id(dstkey) == sig.keyid) { + result = dns_dnssec_verify2(keyname, + &kfetch->dnskeyset, + dstkey, ISC_FALSE, + zone->view->mctx, &sigrr, + dns_fixedname_name(&fixed)); + + dns_zone_log(zone, ISC_LOG_DEBUG(3), + "Verifying DNSKEY set for zone " + "'%s': %s", namebuf, + dns_result_totext(result)); + + if (result == ISC_R_SUCCESS) { + kfetch->dnskeyset.trust = + dns_trust_secure; + kfetch->dnskeysigset.trust = + dns_trust_secure; + dns_keytable_detachkeynode(secroots, + &keynode); + break; + } + } + + result = dns_keytable_nextkeynode(secroots, + keynode, &nextnode); + dns_keytable_detachkeynode(secroots, &keynode); + keynode = nextnode; } + + if (kfetch->dnskeyset.trust == dns_trust_secure) + break; } - pauseall: /* - * Pause all iterators so that dns_db_closeversion() can succeed. + * If we were not able to verify the answer using the current + * trusted keys then all we can do is look at any revoked keys. */ - for (signing = ISC_LIST_HEAD(zone->signing); - signing != NULL; - signing = ISC_LIST_NEXT(signing, link)) - dns_dbiterator_pause(signing->dbiterator); - - for (signing = ISC_LIST_HEAD(cleanup); - signing != NULL; - signing = ISC_LIST_NEXT(signing, link)) - dns_dbiterator_pause(signing->dbiterator); + secure = ISC_TF(kfetch->dnskeyset.trust == dns_trust_secure); /* - * Everything has succeeded. Commit the changes. + * First scan keydataset to find keys that are not in dnskeyset + * - Missing keys which are not scheduled for removal, + * log a warning + * - Missing keys which are scheduled for removal and + * the remove hold-down timer has completed should + * be removed from the key zone + * - Missing keys whose acceptance timers have not yet + * completed, log a warning and reset the acceptance + * timer to 30 days in the future + * - All keys not being removed have their refresh timers + * updated */ - dns_db_closeversion(db, &version, commit); + initializing = ISC_TRUE; + for (result = dns_rdataset_first(&kfetch->keydataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&kfetch->keydataset)) { + dns_rdata_reset(&keydatarr); + dns_rdataset_current(&kfetch->keydataset, &keydatarr); + dns_rdata_tostruct(&keydatarr, &keydata, NULL); + + /* + * If any keydata record has a nonzero add holddown, then + * there was a pre-existing trust anchor for this domain; + * that means we are *not* initializing it and shouldn't + * automatically trust all the keys we find at the zone apex. + */ + initializing = initializing && ISC_TF(keydata.addhd == 0); + + if (! matchkey(&kfetch->dnskeyset, &keydatarr)) { + isc_boolean_t deletekey = ISC_FALSE; + + if (!secure) { + if (now > keydata.removehd) + deletekey = ISC_TRUE; + } else if (now < keydata.addhd) { + dns_zone_log(zone, ISC_LOG_WARNING, + "Pending key unexpectedly missing " + "from %s; restarting acceptance " + "timer", namebuf); + keydata.addhd = now + MONTH; + keydata.refresh = refresh_time(kfetch, + ISC_FALSE); + } else if (keydata.addhd == 0) { + keydata.addhd = now; + } else if (keydata.removehd == 0) { + dns_zone_log(zone, ISC_LOG_WARNING, + "Active key unexpectedly missing " + "from %s", namebuf); + keydata.refresh = now + HOUR; + } else if (now > keydata.removehd) { + deletekey = ISC_TRUE; + } else { + keydata.refresh = refresh_time(kfetch, + ISC_FALSE); + } + + if (secure || deletekey) { + /* Delete old version */ + CHECK(update_one_rr(kfetch->db, ver, &diff, + DNS_DIFFOP_DEL, keyname, 0, + &keydatarr)); + changed = ISC_TRUE; + } + + if (!secure || deletekey) + continue; + + dns_rdata_reset(&keydatarr); + isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); + dns_rdata_fromstruct(&keydatarr, zone->rdclass, + dns_rdatatype_keydata, + &keydata, &keyb); + + /* Insert updated version */ + CHECK(update_one_rr(kfetch->db, ver, &diff, + DNS_DIFFOP_ADD, keyname, 0, + &keydatarr)); + changed = ISC_TRUE; + + set_refreshkeytimer(zone, &keydata, now); + } + } /* - * Everything succeeded so we can clean these up now. + * Next scan dnskeyset: + * - If new keys are found (i.e., lacking a match in keydataset) + * add them to the key zone and set the acceptance timer + * to 30 days in the future (or to immediately if we've + * determined that we're initializing the zone for the + * first time) + * - Previously-known keys that have been revoked + * must be scheduled for removal from the key zone (or, + * if they hadn't been accepted as trust anchors yet + * anyway, removed at once) + * - Previously-known unrevoked keys whose acceptance timers + * have completed are promoted to trust anchors + * - All keys not being removed have their refresh + * timers updated */ - signing = ISC_LIST_HEAD(cleanup); - while (signing != NULL) { - ISC_LIST_UNLINK(cleanup, signing, link); - dns_db_detach(&signing->db); - dns_dbiterator_destroy(&signing->dbiterator); - isc_mem_put(zone->mctx, signing, sizeof *signing); - signing = ISC_LIST_HEAD(cleanup); + for (result = dns_rdataset_first(&kfetch->dnskeyset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&kfetch->dnskeyset)) { + isc_boolean_t revoked = ISC_FALSE; + isc_boolean_t newkey = ISC_FALSE; + isc_boolean_t updatekey = ISC_FALSE; + isc_boolean_t deletekey = ISC_FALSE; + isc_boolean_t trustkey = ISC_FALSE; + + dns_rdata_reset(&dnskeyrr); + dns_rdataset_current(&kfetch->dnskeyset, &dnskeyrr); + dns_rdata_tostruct(&dnskeyrr, &dnskey, NULL); + + /* Skip ZSK's */ + if (!ISC_TF(dnskey.flags & DNS_KEYFLAG_KSK)) + continue; + + revoked = ISC_TF(dnskey.flags & DNS_KEYFLAG_REVOKE); + + if (matchkey(&kfetch->keydataset, &dnskeyrr)) { + dns_rdata_reset(&keydatarr); + dns_rdataset_current(&kfetch->keydataset, &keydatarr); + dns_rdata_tostruct(&keydatarr, &keydata, NULL); + + if (revoked && revocable(kfetch, &keydata)) { + if (keydata.addhd > now) { + /* + * Key wasn't trusted yet, and now + * it's been revoked? Just remove it + */ + deletekey = ISC_TRUE; + } else if (keydata.removehd == 0) { + /* Remove from secroots */ + untrust_key(zone->view->viewlist, + keyname, mctx, &dnskey); + + /* If initializing, delete now */ + if (keydata.addhd == 0) + deletekey = ISC_TRUE; + else + keydata.removehd = now + MONTH; + } else if (keydata.removehd < now) { + /* Scheduled for removal */ + deletekey = ISC_TRUE; + } + } else if (revoked) { + if (secure && keydata.removehd == 0) { + dns_zone_log(zone, ISC_LOG_WARNING, + "Active key for zone " + "'%s' is revoked but " + "did not self-sign; " + "ignoring.", namebuf); + continue; + } + } else if (secure) { + if (keydata.removehd != 0) { + /* + * Key isn't revoked--but it + * seems it used to be. + * Remove it now and add it + * back as if it were a fresh key. + */ + deletekey = ISC_TRUE; + newkey = ISC_TRUE; + } else if (keydata.addhd > now) + pending++; + else if (keydata.addhd == 0) + keydata.addhd = now; + + if (keydata.addhd <= now) + trustkey = ISC_TRUE; + } + + if (!deletekey && !newkey) + updatekey = ISC_TRUE; + } else if (secure) { + /* + * Key wasn't in the key zone but it's + * revoked now anyway, so just skip it + */ + if (revoked) + continue; + + /* Key wasn't in the key zone: add it */ + newkey = ISC_TRUE; + + if (initializing) { + dns_keytag_t tag = 0; + CHECK(compute_tag(keyname, &dnskey, + mctx, &tag)); + dns_zone_log(zone, ISC_LOG_WARNING, + "Initializing automatic trust " + "anchor management for zone '%s'; " + "DNSKEY ID %d is now trusted, " + "waiving the normal 30-day " + "waiting period.", + namebuf, tag); + trustkey = ISC_TRUE; + } + } + + /* Delete old version */ + if (deletekey || !newkey) { + CHECK(update_one_rr(kfetch->db, ver, &diff, + DNS_DIFFOP_DEL, keyname, 0, + &keydatarr)); + changed = ISC_TRUE; + } + + if (updatekey) { + /* Set refresh timer */ + keydata.refresh = refresh_time(kfetch, ISC_FALSE); + dns_rdata_reset(&keydatarr); + isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); + dns_rdata_fromstruct(&keydatarr, zone->rdclass, + dns_rdatatype_keydata, + &keydata, &keyb); + + /* Insert updated version */ + CHECK(update_one_rr(kfetch->db, ver, &diff, + DNS_DIFFOP_ADD, keyname, 0, + &keydatarr)); + changed = ISC_TRUE; + } else if (newkey) { + /* Convert DNSKEY to KEYDATA */ + dns_rdata_tostruct(&dnskeyrr, &dnskey, NULL); + dns_keydata_fromdnskey(&keydata, &dnskey, 0, 0, 0, + NULL); + keydata.addhd = initializing ? now : now + MONTH; + keydata.refresh = refresh_time(kfetch, ISC_FALSE); + dns_rdata_reset(&keydatarr); + isc_buffer_init(&keyb, key_buf, sizeof(key_buf)); + dns_rdata_fromstruct(&keydatarr, zone->rdclass, + dns_rdatatype_keydata, + &keydata, &keyb); + + /* Insert into key zone */ + CHECK(update_one_rr(kfetch->db, ver, &diff, + DNS_DIFFOP_ADD, keyname, 0, + &keydatarr)); + changed = ISC_TRUE; + } + + if (trustkey) { + /* Trust this key in all views */ + dns_rdata_tostruct(&dnskeyrr, &dnskey, NULL); + trust_key(zone->view->viewlist, keyname, &dnskey, + mctx); + } + + if (!deletekey) + set_refreshkeytimer(zone, &keydata, now); + } + + /* + * RFC5011 says, "A trust point that has all of its trust anchors + * revoked is considered deleted and is treated as if the trust + * point was never configured." But if someone revoked their + * active key before the standby was trusted, that would mean the + * zone would suddenly be nonsecured. We avoid this by checking to + * see if there's pending keydata. If so, we put a null key in + * the security roots; then all queries to the zone will fail. + */ + if (pending != 0) + fail_secure(zone->view->viewlist, keyname); + + failure: + if (changed) { + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); + zone_needdump(zone, 30); } - set_resigntime(zone); + UNLOCK_ZONE(zone); + + /* Write changes to journal file. */ + if (alldone) { + result = increment_soa_serial(kfetch->db, ver, &diff, mctx); + if (result == ISC_R_SUCCESS) + result = zone_journal(zone, &diff, "keyfetch_done"); + } + + dns_diff_clear(&diff); + dns_db_closeversion(kfetch->db, &ver, changed); + dns_db_detach(&kfetch->db); + dns_zone_detach(&kfetch->zone); + + if (dns_rdataset_isassociated(&kfetch->keydataset)) + dns_rdataset_disassociate(&kfetch->keydataset); + if (dns_rdataset_isassociated(&kfetch->dnskeyset)) + dns_rdataset_disassociate(&kfetch->dnskeyset); + if (dns_rdataset_isassociated(&kfetch->dnskeysigset)) + dns_rdataset_disassociate(&kfetch->dnskeysigset); + + dns_name_free(keyname, mctx); + isc_mem_put(mctx, kfetch, sizeof(dns_keyfetch_t)); + isc_mem_detach(&mctx); + + if (secroots != NULL) + dns_keytable_detach(&secroots); +} + +/* + * Refresh the data in the key zone. Initiate a fetch to get new DNSKEY + * records from the zone apex. + */ +static void +zone_refreshkeys(dns_zone_t *zone) { + const char me[] = "zone_refreshkeys"; + isc_result_t result; + dns_rriterator_t rrit; + dns_db_t *db = NULL; + dns_dbversion_t *ver = NULL; + dns_diff_t diff; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_keydata_t kd; + isc_stdtime_t now; + isc_boolean_t commit = ISC_FALSE; + + ENTER; + REQUIRE(zone->db != NULL); + + isc_stdtime_get(&now); + + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + dns_db_attach(zone->db, &db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + + LOCK_ZONE(zone); + dns_db_newversion(db, &ver); + dns_diff_init(zone->mctx, &diff); + + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESHING); + + dns_rriterator_init(&rrit, db, ver, 0); + for (result = dns_rriterator_first(&rrit); + result == ISC_R_SUCCESS; + result = dns_rriterator_nextrrset(&rrit)) { + isc_stdtime_t timer = 0xffffffff; + dns_keyfetch_t *kfetch; + dns_rdataset_t *kdset; + dns_name_t *name = NULL; + isc_uint32_t ttl; + + dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL); + if (!dns_rdataset_isassociated(kdset)) + continue; + + if (kdset->type != dns_rdatatype_keydata) + continue; - if (commit) { - LOCK_ZONE(zone); - zone_needdump(zone, DNS_DUMP_DELAY); - UNLOCK_ZONE(zone); - } + /* + * Scan the stored keys looking for ones that need + * removal or refreshing + */ + for (result = dns_rdataset_first(kdset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(kdset)) { + dns_rdata_reset(&rdata); + dns_rdataset_current(kdset, &rdata); + result = dns_rdata_tostruct(&rdata, &kd, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); - failure: - /* - * Rollback the cleanup list. - */ - signing = ISC_LIST_HEAD(cleanup); - while (signing != NULL) { - ISC_LIST_UNLINK(cleanup, signing, link); - ISC_LIST_APPEND(zone->signing, signing, link); - dns_dbiterator_first(signing->dbiterator); - dns_dbiterator_pause(signing->dbiterator); - signing = ISC_LIST_HEAD(cleanup); - } + /* Removal timer expired? */ + if (kd.removehd != 0 && kd.removehd < now) { + CHECK(update_one_rr(db, ver, &diff, + DNS_DIFFOP_DEL, name, ttl, + &rdata)); + continue; + } - for (signing = ISC_LIST_HEAD(zone->signing); - signing != NULL; - signing = ISC_LIST_NEXT(signing, link)) - dns_dbiterator_pause(signing->dbiterator); + /* Acceptance timer expired? */ + if (kd.addhd != 0 && kd.addhd < now) + timer = kd.addhd; - dns_diff_clear(&sig_diff); + /* Or do we just need to refresh the keyset? */ + if (timer > kd.refresh) + timer = kd.refresh; + } - for (i = 0; i < nkeys; i++) - dst_key_free(&zone_keys[i]); + if (timer > now) + continue; - if (version != NULL) { - dns_db_closeversion(db, &version, ISC_FALSE); - dns_db_detach(&db); - } else if (db != NULL) - dns_db_detach(&db); + zone->refreshkeycount++; + + kfetch = isc_mem_get(zone->mctx, sizeof(dns_keyfetch_t)); + kfetch->zone = NULL; + dns_zone_attach(zone, &kfetch->zone); + dns_fixedname_init(&kfetch->name); + dns_name_dup(name, zone->mctx, + dns_fixedname_name(&kfetch->name)); + dns_rdataset_init(&kfetch->dnskeyset); + dns_rdataset_init(&kfetch->dnskeysigset); + dns_rdataset_init(&kfetch->keydataset); + dns_rdataset_clone(kdset, &kfetch->keydataset); + kfetch->db = NULL; + dns_db_attach(db, &kfetch->db); + kfetch->fetch = NULL; + + dns_resolver_createfetch(zone->view->resolver, + dns_fixedname_name(&kfetch->name), + dns_rdatatype_dnskey, + NULL, NULL, NULL, + DNS_FETCHOPT_NOVALIDATE, + zone->task, keyfetch_done, kfetch, + &kfetch->dnskeyset, + &kfetch->dnskeysigset, + &kfetch->fetch); + } + if (!ISC_LIST_EMPTY(diff.tuples)) { + CHECK(increment_soa_serial(db, ver, &diff, zone->mctx)); + commit = ISC_TRUE; + zone_journal(zone, &diff, "sync_keyzone"); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED); + zone_needdump(zone, 30); + } + failure: + UNLOCK_ZONE(zone); - if (ISC_LIST_HEAD(zone->signing) != NULL) { - isc_interval_t i; - if (zone->update_disabled || result != ISC_R_SUCCESS) - isc_interval_set(&i, 60, 0); /* 1 minute */ - else - isc_interval_set(&i, 0, 10000000); /* 10 ms */ - isc_time_nowplusinterval(&zone->signingtime, &i); - } else - isc_time_settoepoch(&zone->signingtime); + dns_rriterator_destroy(&rrit); + dns_diff_clear(&diff); + dns_db_closeversion(db, &ver, commit); + dns_db_detach(&db); } static void @@ -5991,7 +7790,7 @@ zone_maintenance(dns_zone_t *zone) { /* * Configuring the view of this zone may have * failed, for example because the config file - * had a syntax error. In that case, the view + * had a syntax error. In that case, the view * adb or resolver, and we had better not try * to do maintenance on it. */ @@ -6038,6 +7837,7 @@ zone_maintenance(dns_zone_t *zone) { switch (zone->type) { case dns_zone_master: case dns_zone_slave: + case dns_zone_key: LOCK_ZONE(zone); if (zone->masterfile != NULL && isc_time_compare(&now, &zone->dumptime) >= 0 && @@ -6059,6 +7859,24 @@ zone_maintenance(dns_zone_t *zone) { break; } + /* + * Do we need to refresh keys? + */ + switch (zone->type) { + case dns_zone_key: + if (isc_time_compare(&now, &zone->refreshkeytime) >= 0 && + DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING)) + zone_refreshkeys(zone); + break; + case dns_zone_master: + if (!isc_time_isepoch(&zone->refreshkeytime) && + isc_time_compare(&now, &zone->refreshkeytime) >= 0) + zone_rekey(zone); + default: + break; + } + switch (zone->type) { case dns_zone_master: case dns_zone_slave: @@ -6098,7 +7916,8 @@ void dns_zone_markdirty(dns_zone_t *zone) { LOCK_ZONE(zone); - set_resigntime(zone); /* XXXMPA make separate call back */ + if (zone->type == dns_zone_master) + set_resigntime(zone); /* XXXMPA make separate call back */ zone_needdump(zone, DNS_DUMP_DELAY); UNLOCK_ZONE(zone); } @@ -7087,154 +8906,411 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { result = dns_name_dup(&ns.name, zone->mctx, ¬ify->ns); if (result != ISC_R_SUCCESS) { LOCK_ZONE(zone); - notify_destroy(notify, ISC_TRUE); + notify_destroy(notify, ISC_TRUE); + UNLOCK_ZONE(zone); + continue; + } + LOCK_ZONE(zone); + ISC_LIST_APPEND(zone->notifies, notify, link); + UNLOCK_ZONE(zone); + notify_find_address(notify); + notify = NULL; + result = dns_rdataset_next(&nsrdset); + } + dns_rdataset_disassociate(&nsrdset); + + cleanup3: + if (dns_name_dynamic(&master)) + dns_name_free(&master, zone->mctx); + cleanup2: + dns_db_detachnode(zonedb, &node); + cleanup1: + dns_db_closeversion(zonedb, &version, ISC_FALSE); + dns_db_detach(&zonedb); +} + +/*** + *** Private + ***/ + +static inline isc_result_t +save_nsrrset(dns_message_t *message, dns_name_t *name, + dns_db_t *db, dns_dbversion_t *version) +{ + dns_rdataset_t *nsrdataset = NULL; + dns_rdataset_t *rdataset = NULL; + dns_dbnode_t *node = NULL; + dns_rdata_ns_t ns; + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; + + /* + * Extract NS RRset from message. + */ + result = dns_message_findname(message, DNS_SECTION_ANSWER, name, + dns_rdatatype_ns, dns_rdatatype_none, + NULL, &nsrdataset); + if (result != ISC_R_SUCCESS) + goto fail; + + /* + * Add NS rdataset. + */ + result = dns_db_findnode(db, name, ISC_TRUE, &node); + if (result != ISC_R_SUCCESS) + goto fail; + result = dns_db_addrdataset(db, node, version, 0, + nsrdataset, 0, NULL); + dns_db_detachnode(db, &node); + if (result != ISC_R_SUCCESS) + goto fail; + /* + * Add glue rdatasets. + */ + for (result = dns_rdataset_first(nsrdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(nsrdataset)) { + dns_rdataset_current(nsrdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &ns, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_rdata_reset(&rdata); + if (!dns_name_issubdomain(&ns.name, name)) + continue; + rdataset = NULL; + result = dns_message_findname(message, DNS_SECTION_ADDITIONAL, + &ns.name, dns_rdatatype_aaaa, + dns_rdatatype_none, NULL, + &rdataset); + if (result == ISC_R_SUCCESS) { + result = dns_db_findnode(db, &ns.name, + ISC_TRUE, &node); + if (result != ISC_R_SUCCESS) + goto fail; + result = dns_db_addrdataset(db, node, version, 0, + rdataset, 0, NULL); + dns_db_detachnode(db, &node); + if (result != ISC_R_SUCCESS) + goto fail; + } + rdataset = NULL; + result = dns_message_findname(message, DNS_SECTION_ADDITIONAL, + &ns.name, dns_rdatatype_a, + dns_rdatatype_none, NULL, + &rdataset); + if (result == ISC_R_SUCCESS) { + result = dns_db_findnode(db, &ns.name, + ISC_TRUE, &node); + if (result != ISC_R_SUCCESS) + goto fail; + result = dns_db_addrdataset(db, node, version, 0, + rdataset, 0, NULL); + dns_db_detachnode(db, &node); + if (result != ISC_R_SUCCESS) + goto fail; + } + } + if (result != ISC_R_NOMORE) + goto fail; + + return (ISC_R_SUCCESS); + +fail: + return (result); +} + +static void +stub_callback(isc_task_t *task, isc_event_t *event) { + const char me[] = "stub_callback"; + dns_requestevent_t *revent = (dns_requestevent_t *)event; + dns_stub_t *stub = NULL; + dns_message_t *msg = NULL; + dns_zone_t *zone = NULL; + char master[ISC_SOCKADDR_FORMATSIZE]; + char source[ISC_SOCKADDR_FORMATSIZE]; + isc_uint32_t nscnt, cnamecnt; + isc_result_t result; + isc_time_t now; + isc_boolean_t exiting = ISC_FALSE; + isc_interval_t i; + unsigned int j; + + stub = revent->ev_arg; + INSIST(DNS_STUB_VALID(stub)); + + UNUSED(task); + + zone = stub->zone; + + ENTER; + + TIME_NOW(&now); + + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { + zone_debuglog(zone, me, 1, "exiting"); + exiting = ISC_TRUE; + goto next_master; + } + + isc_sockaddr_format(&zone->masteraddr, master, sizeof(master)); + isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source)); + + if (revent->result != ISC_R_SUCCESS) { + if (revent->result == ISC_R_TIMEDOUT && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); + UNLOCK_ZONE(zone); + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "refreshing stub: timeout retrying " + " without EDNS master %s (source %s)", + master, source); + goto same_master; + } + dns_zonemgr_unreachableadd(zone->zmgr, &zone->masteraddr, + &zone->sourceaddr, &now); + dns_zone_log(zone, ISC_LOG_INFO, + "could not refresh stub from master %s" + " (source %s): %s", master, source, + dns_result_totext(revent->result)); + goto next_master; + } + + result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTPARSE, &msg); + if (result != ISC_R_SUCCESS) + goto next_master; + + result = dns_request_getresponse(revent->request, msg, 0); + if (result != ISC_R_SUCCESS) + goto next_master; + + /* + * Unexpected rcode. + */ + if (msg->rcode != dns_rcode_noerror) { + char rcode[128]; + isc_buffer_t rb; + + isc_buffer_init(&rb, rcode, sizeof(rcode)); + (void)dns_rcode_totext(msg->rcode, &rb); + + if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS) && + (msg->rcode == dns_rcode_servfail || + msg->rcode == dns_rcode_notimp || + msg->rcode == dns_rcode_formerr)) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "refreshing stub: rcode (%.*s) retrying " + "without EDNS master %s (source %s)", + (int)rb.used, rcode, master, source); + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); UNLOCK_ZONE(zone); - continue; + goto same_master; + } + + dns_zone_log(zone, ISC_LOG_INFO, + "refreshing stub: " + "unexpected rcode (%.*s) from %s (source %s)", + (int)rb.used, rcode, master, source); + goto next_master; + } + + /* + * We need complete messages. + */ + if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { + if (dns_request_usedtcp(revent->request)) { + dns_zone_log(zone, ISC_LOG_INFO, + "refreshing stub: truncated TCP " + "response from master %s (source %s)", + master, source); + goto next_master; } LOCK_ZONE(zone); - ISC_LIST_APPEND(zone->notifies, notify, link); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEVC); UNLOCK_ZONE(zone); - notify_find_address(notify); - notify = NULL; - result = dns_rdataset_next(&nsrdset); + goto same_master; } - dns_rdataset_disassociate(&nsrdset); - cleanup3: - if (dns_name_dynamic(&master)) - dns_name_free(&master, zone->mctx); - cleanup2: - dns_db_detachnode(zonedb, &node); - cleanup1: - dns_db_closeversion(zonedb, &version, ISC_FALSE); - dns_db_detach(&zonedb); -} + /* + * If non-auth log and next master. + */ + if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) { + dns_zone_log(zone, ISC_LOG_INFO, "refreshing stub: " + "non-authoritative answer from " + "master %s (source %s)", master, source); + goto next_master; + } -/*** - *** Private - ***/ + /* + * Sanity checks. + */ + cnamecnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_cname); + nscnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_ns); -static inline isc_result_t -save_nsrrset(dns_message_t *message, dns_name_t *name, - dns_db_t *db, dns_dbversion_t *version) -{ - dns_rdataset_t *nsrdataset = NULL; - dns_rdataset_t *rdataset = NULL; - dns_dbnode_t *node = NULL; - dns_rdata_ns_t ns; - isc_result_t result; - dns_rdata_t rdata = DNS_RDATA_INIT; + if (cnamecnt != 0) { + dns_zone_log(zone, ISC_LOG_INFO, + "refreshing stub: unexpected CNAME response " + "from master %s (source %s)", master, source); + goto next_master; + } + + if (nscnt == 0) { + dns_zone_log(zone, ISC_LOG_INFO, + "refreshing stub: no NS records in response " + "from master %s (source %s)", master, source); + goto next_master; + } /* - * Extract NS RRset from message. + * Save answer. */ - result = dns_message_findname(message, DNS_SECTION_ANSWER, name, - dns_rdatatype_ns, dns_rdatatype_none, - NULL, &nsrdataset); - if (result != ISC_R_SUCCESS) - goto fail; + result = save_nsrrset(msg, &zone->origin, stub->db, stub->version); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_INFO, + "refreshing stub: unable to save NS records " + "from master %s (source %s)", master, source); + goto next_master; + } /* - * Add NS rdataset. + * Tidy up. */ - result = dns_db_findnode(db, name, ISC_TRUE, &node); - if (result != ISC_R_SUCCESS) - goto fail; - result = dns_db_addrdataset(db, node, version, 0, - nsrdataset, 0, NULL); - dns_db_detachnode(db, &node); - if (result != ISC_R_SUCCESS) - goto fail; + dns_db_closeversion(stub->db, &stub->version, ISC_TRUE); + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); + if (zone->db == NULL) + zone_attachdb(zone, stub->db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); + dns_db_detach(&stub->db); + + if (zone->masterfile != NULL) { + dns_zone_dump(zone); + TIME_NOW(&zone->loadtime); + } + + dns_message_destroy(&msg); + isc_event_free(&event); + LOCK_ZONE(zone); + dns_request_destroy(&zone->request); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); + DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime); + isc_interval_set(&i, zone->expire, 0); + DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime); + zone_settimer(zone, &now); + UNLOCK_ZONE(zone); + goto free_stub; + + next_master: + if (stub->version != NULL) + dns_db_closeversion(stub->db, &stub->version, ISC_FALSE); + if (stub->db != NULL) + dns_db_detach(&stub->db); + if (msg != NULL) + dns_message_destroy(&msg); + isc_event_free(&event); + LOCK_ZONE(zone); + dns_request_destroy(&zone->request); /* - * Add glue rdatasets. + * Skip to next failed / untried master. */ - for (result = dns_rdataset_first(nsrdataset); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(nsrdataset)) { - dns_rdataset_current(nsrdataset, &rdata); - result = dns_rdata_tostruct(&rdata, &ns, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - dns_rdata_reset(&rdata); - if (!dns_name_issubdomain(&ns.name, name)) - continue; - rdataset = NULL; - result = dns_message_findname(message, DNS_SECTION_ADDITIONAL, - &ns.name, dns_rdatatype_aaaa, - dns_rdatatype_none, NULL, - &rdataset); - if (result == ISC_R_SUCCESS) { - result = dns_db_findnode(db, &ns.name, - ISC_TRUE, &node); - if (result != ISC_R_SUCCESS) - goto fail; - result = dns_db_addrdataset(db, node, version, 0, - rdataset, 0, NULL); - dns_db_detachnode(db, &node); - if (result != ISC_R_SUCCESS) - goto fail; - } - rdataset = NULL; - result = dns_message_findname(message, DNS_SECTION_ADDITIONAL, - &ns.name, dns_rdatatype_a, - dns_rdatatype_none, NULL, - &rdataset); - if (result == ISC_R_SUCCESS) { - result = dns_db_findnode(db, &ns.name, - ISC_TRUE, &node); - if (result != ISC_R_SUCCESS) - goto fail; - result = dns_db_addrdataset(db, node, version, 0, - rdataset, 0, NULL); - dns_db_detachnode(db, &node); - if (result != ISC_R_SUCCESS) - goto fail; + do { + zone->curmaster++; + } while (zone->curmaster < zone->masterscnt && + zone->mastersok[zone->curmaster]); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS); + if (exiting || zone->curmaster >= zone->masterscnt) { + isc_boolean_t done = ISC_TRUE; + if (!exiting && + DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { + /* + * Did we get a good answer from all the masters? + */ + for (j = 0; j < zone->masterscnt; j++) + if (zone->mastersok[j] == ISC_FALSE) { + done = ISC_FALSE; + break; + } + } else + done = ISC_TRUE; + if (!done) { + zone->curmaster = 0; + /* + * Find the next failed master. + */ + while (zone->curmaster < zone->masterscnt && + zone->mastersok[zone->curmaster]) + zone->curmaster++; + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); + } else { + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); + + zone_settimer(zone, &now); + UNLOCK_ZONE(zone); + goto free_stub; } } - if (result != ISC_R_NOMORE) - goto fail; + queue_soa_query(zone); + UNLOCK_ZONE(zone); + goto free_stub; - return (ISC_R_SUCCESS); + same_master: + if (msg != NULL) + dns_message_destroy(&msg); + isc_event_free(&event); + LOCK_ZONE(zone); + dns_request_destroy(&zone->request); + UNLOCK_ZONE(zone); + ns_query(zone, NULL, stub); + goto done; -fail: - return (result); + free_stub: + stub->magic = 0; + dns_zone_idetach(&stub->zone); + INSIST(stub->db == NULL); + INSIST(stub->version == NULL); + isc_mem_put(stub->mctx, stub, sizeof(*stub)); + + done: + INSIST(event == NULL); + return; } +/* + * An SOA query has finished (successfully or not). + */ static void -stub_callback(isc_task_t *task, isc_event_t *event) { - const char me[] = "stub_callback"; +refresh_callback(isc_task_t *task, isc_event_t *event) { + const char me[] = "refresh_callback"; dns_requestevent_t *revent = (dns_requestevent_t *)event; - dns_stub_t *stub = NULL; + dns_zone_t *zone; dns_message_t *msg = NULL; - dns_zone_t *zone = NULL; + isc_uint32_t soacnt, cnamecnt, soacount, nscount; + isc_time_t now; char master[ISC_SOCKADDR_FORMATSIZE]; char source[ISC_SOCKADDR_FORMATSIZE]; - isc_uint32_t nscnt, cnamecnt; + dns_rdataset_t *rdataset = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_soa_t soa; isc_result_t result; - isc_time_t now; - isc_boolean_t exiting = ISC_FALSE; - isc_interval_t i; + isc_uint32_t serial, oldserial; unsigned int j; - stub = revent->ev_arg; - INSIST(DNS_STUB_VALID(stub)); + zone = revent->ev_arg; + INSIST(DNS_ZONE_VALID(zone)); UNUSED(task); - zone = stub->zone; - ENTER; - TIME_NOW(&now); - - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { - zone_debuglog(zone, me, 1, "exiting"); - exiting = ISC_TRUE; - goto next_master; - } + /* + * if timeout log and next master; + */ isc_sockaddr_format(&zone->masteraddr, master, sizeof(master)); isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source)); + TIME_NOW(&now); + if (revent->result != ISC_R_SUCCESS) { if (revent->result == ISC_R_TIMEDOUT && !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { @@ -7242,27 +9318,54 @@ stub_callback(isc_task_t *task, isc_event_t *event) { DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); UNLOCK_ZONE(zone); dns_zone_log(zone, ISC_LOG_DEBUG(1), - "refreshing stub: timeout retrying " - " without EDNS master %s (source %s)", - master, source); + "refresh: timeout retrying without EDNS " + "master %s (source %s)", master, source); goto same_master; } - dns_zonemgr_unreachableadd(zone->zmgr, &zone->masteraddr, - &zone->sourceaddr, &now); - dns_zone_log(zone, ISC_LOG_INFO, - "could not refresh stub from master %s" - " (source %s): %s", master, source, - dns_result_totext(revent->result)); + if (revent->result == ISC_R_TIMEDOUT && + !dns_request_usedtcp(revent->request)) { + dns_zone_log(zone, ISC_LOG_INFO, + "refresh: retry limit for " + "master %s exceeded (source %s)", + master, source); + /* Try with slave with TCP. */ + if (zone->type == dns_zone_slave && + DNS_ZONE_OPTION(zone, DNS_ZONEOPT_TRYTCPREFRESH)) { + if (!dns_zonemgr_unreachable(zone->zmgr, + &zone->masteraddr, + &zone->sourceaddr, + &now)) { + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, + DNS_ZONEFLG_SOABEFOREAXFR); + UNLOCK_ZONE(zone); + goto tcp_transfer; + } + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "refresh: skipped tcp fallback" + "as master %s (source %s) is " + "unreachable (cached)", + master, source); + } + } else + dns_zone_log(zone, ISC_LOG_INFO, + "refresh: failure trying master " + "%s (source %s): %s", master, source, + dns_result_totext(revent->result)); goto next_master; } result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTPARSE, &msg); if (result != ISC_R_SUCCESS) goto next_master; - result = dns_request_getresponse(revent->request, msg, 0); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_INFO, + "refresh: failure trying master " + "%s (source %s): %s", master, source, + dns_result_totext(result)); goto next_master; + } /* * Unexpected rcode. @@ -7279,112 +9382,217 @@ stub_callback(isc_task_t *task, isc_event_t *event) { msg->rcode == dns_rcode_notimp || msg->rcode == dns_rcode_formerr)) { dns_zone_log(zone, ISC_LOG_DEBUG(1), - "refreshing stub: rcode (%.*s) retrying " - "without EDNS master %s (source %s)", + "refresh: rcode (%.*s) retrying without " + "EDNS master %s (source %s)", (int)rb.used, rcode, master, source); LOCK_ZONE(zone); DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); UNLOCK_ZONE(zone); goto same_master; } - dns_zone_log(zone, ISC_LOG_INFO, - "refreshing stub: " - "unexpected rcode (%.*s) from %s (source %s)", - (int)rb.used, rcode, master, source); + "refresh: unexpected rcode (%.*s) from " + "master %s (source %s)", (int)rb.used, rcode, + master, source); + /* + * Perhaps AXFR/IXFR is allowed even if SOA queries aren't. + */ + if (msg->rcode == dns_rcode_refused && + zone->type == dns_zone_slave) + goto tcp_transfer; goto next_master; } /* - * We need complete messages. + * If truncated punt to zone transfer which will query again. */ if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { - if (dns_request_usedtcp(revent->request)) { + if (zone->type == dns_zone_slave) { dns_zone_log(zone, ISC_LOG_INFO, - "refreshing stub: truncated TCP " - "response from master %s (source %s)", + "refresh: truncated UDP answer, " + "initiating TCP zone xfer " + "for master %s (source %s)", + master, source); + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR); + UNLOCK_ZONE(zone); + goto tcp_transfer; + } else { + INSIST(zone->type == dns_zone_stub); + if (dns_request_usedtcp(revent->request)) { + dns_zone_log(zone, ISC_LOG_INFO, + "refresh: truncated TCP response " + "from master %s (source %s)", + master, source); + goto next_master; + } + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEVC); + UNLOCK_ZONE(zone); + goto same_master; + } + } + + /* + * if non-auth log and next master; + */ + if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) { + dns_zone_log(zone, ISC_LOG_INFO, + "refresh: non-authoritative answer from " + "master %s (source %s)", master, source); + goto next_master; + } + + cnamecnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_cname); + soacnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_soa); + nscount = message_count(msg, DNS_SECTION_AUTHORITY, dns_rdatatype_ns); + soacount = message_count(msg, DNS_SECTION_AUTHORITY, + dns_rdatatype_soa); + + /* + * There should not be a CNAME record at top of zone. + */ + if (cnamecnt != 0) { + dns_zone_log(zone, ISC_LOG_INFO, + "refresh: CNAME at top of zone " + "in master %s (source %s)", master, source); + goto next_master; + } + + /* + * if referral log and next master; + */ + if (soacnt == 0 && soacount == 0 && nscount != 0) { + dns_zone_log(zone, ISC_LOG_INFO, + "refresh: referral response " + "from master %s (source %s)", master, source); + goto next_master; + } + + /* + * if nodata log and next master; + */ + if (soacnt == 0 && (nscount == 0 || soacount != 0)) { + dns_zone_log(zone, ISC_LOG_INFO, + "refresh: NODATA response " + "from master %s (source %s)", master, source); + goto next_master; + } + + /* + * Only one soa at top of zone. + */ + if (soacnt != 1) { + dns_zone_log(zone, ISC_LOG_INFO, + "refresh: answer SOA count (%d) != 1 " + "from master %s (source %s)", + soacnt, master, source); + goto next_master; + } + /* + * Extract serial + */ + rdataset = NULL; + result = dns_message_findname(msg, DNS_SECTION_ANSWER, &zone->origin, + dns_rdatatype_soa, dns_rdatatype_none, + NULL, &rdataset); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_INFO, + "refresh: unable to get SOA record " + "from master %s (source %s)", master, source); + goto next_master; + } + + result = dns_rdataset_first(rdataset); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_INFO, + "refresh: dns_rdataset_first() failed"); + goto next_master; + } + + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &soa, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + serial = soa.serial; + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) { + result = dns_zone_getserial2(zone, &oldserial); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + zone_debuglog(zone, me, 1, "serial: new %u, old %u", + serial, oldserial); + } else + zone_debuglog(zone, me, 1, "serial: new %u, old not loaded", + serial); + if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) || + DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER) || + isc_serial_gt(serial, oldserial)) { + if (dns_zonemgr_unreachable(zone->zmgr, &zone->masteraddr, + &zone->sourceaddr, &now)) { + dns_zone_log(zone, ISC_LOG_INFO, + "refresh: skipping %s as master %s " + "(source %s) is unreachable (cached)", + zone->type == dns_zone_slave ? + "zone transfer" : "NS query", master, source); goto next_master; } - LOCK_ZONE(zone); - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEVC); - UNLOCK_ZONE(zone); - goto same_master; - } - - /* - * If non-auth log and next master. - */ - if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) { - dns_zone_log(zone, ISC_LOG_INFO, "refreshing stub: " - "non-authoritative answer from " - "master %s (source %s)", master, source); - goto next_master; - } - - /* - * Sanity checks. - */ - cnamecnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_cname); - nscnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_ns); - - if (cnamecnt != 0) { - dns_zone_log(zone, ISC_LOG_INFO, - "refreshing stub: unexpected CNAME response " - "from master %s (source %s)", master, source); - goto next_master; - } - - if (nscnt == 0) { - dns_zone_log(zone, ISC_LOG_INFO, - "refreshing stub: no NS records in response " - "from master %s (source %s)", master, source); + tcp_transfer: + isc_event_free(&event); + LOCK_ZONE(zone); + dns_request_destroy(&zone->request); + UNLOCK_ZONE(zone); + if (zone->type == dns_zone_slave) { + queue_xfrin(zone); + } else { + INSIST(zone->type == dns_zone_stub); + ns_query(zone, rdataset, NULL); + } + if (msg != NULL) + dns_message_destroy(&msg); + } else if (isc_serial_eq(soa.serial, oldserial)) { + if (zone->masterfile != NULL) { + result = ISC_R_FAILURE; + if (zone->journal != NULL) + result = isc_file_settime(zone->journal, &now); + if (result == ISC_R_SUCCESS && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { + result = isc_file_settime(zone->masterfile, + &now); + } else if (result != ISC_R_SUCCESS) + result = isc_file_settime(zone->masterfile, + &now); + /* Someone removed the file from underneath us! */ + if (result == ISC_R_FILENOTFOUND) { + LOCK_ZONE(zone); + zone_needdump(zone, DNS_DUMP_DELAY); + UNLOCK_ZONE(zone); + } else if (result != ISC_R_SUCCESS) + dns_zone_log(zone, ISC_LOG_ERROR, + "refresh: could not set file " + "modification time of '%s': %s", + zone->masterfile, + dns_result_totext(result)); + } + DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime); + DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime); + zone->mastersok[zone->curmaster] = ISC_TRUE; goto next_master; - } - - /* - * Save answer. - */ - result = save_nsrrset(msg, &zone->origin, stub->db, stub->version); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_INFO, - "refreshing stub: unable to save NS records " - "from master %s (source %s)", master, source); + } else { + if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MULTIMASTER)) + dns_zone_log(zone, ISC_LOG_INFO, "serial number (%u) " + "received from master %s < ours (%u)", + soa.serial, master, oldserial); + else + zone_debuglog(zone, me, 1, "ahead"); + zone->mastersok[zone->curmaster] = ISC_TRUE; goto next_master; } - - /* - * Tidy up. - */ - dns_db_closeversion(stub->db, &stub->version, ISC_TRUE); - ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); - if (zone->db == NULL) - zone_attachdb(zone, stub->db); - ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); - dns_db_detach(&stub->db); - - if (zone->masterfile != NULL) { - dns_zone_dump(zone); - TIME_NOW(&zone->loadtime); - } - - dns_message_destroy(&msg); - isc_event_free(&event); - LOCK_ZONE(zone); - dns_request_destroy(&zone->request); - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); - DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime); - isc_interval_set(&i, zone->expire, 0); - DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime); - zone_settimer(zone, &now); - UNLOCK_ZONE(zone); - goto free_stub; + if (msg != NULL) + dns_message_destroy(&msg); + goto detach; next_master: - if (stub->version != NULL) - dns_db_closeversion(stub->db, &stub->version, ISC_FALSE); - if (stub->db != NULL) - dns_db_detach(&stub->db); if (msg != NULL) dns_message_destroy(&msg); isc_event_free(&event); @@ -7398,10 +9606,9 @@ stub_callback(isc_task_t *task, isc_event_t *event) { } while (zone->curmaster < zone->masterscnt && zone->mastersok[zone->curmaster]); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS); - if (exiting || zone->curmaster >= zone->masterscnt) { + if (zone->curmaster >= zone->masterscnt) { isc_boolean_t done = ISC_TRUE; - if (!exiting && - DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) && + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) && !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { /* * Did we get a good answer from all the masters? @@ -7414,6 +9621,7 @@ stub_callback(isc_task_t *task, isc_event_t *event) { } else done = ISC_TRUE; if (!done) { + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); zone->curmaster = 0; /* * Find the next failed master. @@ -7421,4224 +9629,4643 @@ stub_callback(isc_task_t *task, isc_event_t *event) { while (zone->curmaster < zone->masterscnt && zone->mastersok[zone->curmaster]) zone->curmaster++; - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); - } else { - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); + goto requeue; + } + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDREFRESH)) { + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDREFRESH); + zone->refreshtime = now; + } + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); + zone_settimer(zone, &now); + UNLOCK_ZONE(zone); + goto detach; + } + + requeue: + queue_soa_query(zone); + UNLOCK_ZONE(zone); + goto detach; + + same_master: + if (msg != NULL) + dns_message_destroy(&msg); + isc_event_free(&event); + LOCK_ZONE(zone); + dns_request_destroy(&zone->request); + queue_soa_query(zone); + UNLOCK_ZONE(zone); + + detach: + dns_zone_idetach(&zone); + return; +} + +static void +queue_soa_query(dns_zone_t *zone) { + const char me[] = "queue_soa_query"; + isc_event_t *e; + dns_zone_t *dummy = NULL; + isc_result_t result; + + ENTER; + /* + * Locked by caller + */ + REQUIRE(LOCKED_ZONE(zone)); + + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { + cancel_refresh(zone); + return; + } + + e = isc_event_allocate(zone->mctx, NULL, DNS_EVENT_ZONE, + soa_query, zone, sizeof(isc_event_t)); + if (e == NULL) { + cancel_refresh(zone); + return; + } + + /* + * Attach so that we won't clean up + * until the event is delivered. + */ + zone_iattach(zone, &dummy); + + e->ev_arg = zone; + e->ev_sender = NULL; + result = isc_ratelimiter_enqueue(zone->zmgr->rl, zone->task, &e); + if (result != ISC_R_SUCCESS) { + zone_idetach(&dummy); + isc_event_free(&e); + cancel_refresh(zone); + } +} + +static inline isc_result_t +create_query(dns_zone_t *zone, dns_rdatatype_t rdtype, + dns_message_t **messagep) +{ + dns_message_t *message = NULL; + dns_name_t *qname = NULL; + dns_rdataset_t *qrdataset = NULL; + isc_result_t result; + + result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTRENDER, + &message); + if (result != ISC_R_SUCCESS) + goto cleanup; + + message->opcode = dns_opcode_query; + message->rdclass = zone->rdclass; + + result = dns_message_gettempname(message, &qname); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dns_message_gettemprdataset(message, &qrdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + + /* + * Make question. + */ + dns_name_init(qname, NULL); + dns_name_clone(&zone->origin, qname); + dns_rdataset_init(qrdataset); + dns_rdataset_makequestion(qrdataset, zone->rdclass, rdtype); + ISC_LIST_APPEND(qname->list, qrdataset, link); + dns_message_addname(message, qname, DNS_SECTION_QUESTION); + + *messagep = message; + return (ISC_R_SUCCESS); + + cleanup: + if (qname != NULL) + dns_message_puttempname(message, &qname); + if (qrdataset != NULL) + dns_message_puttemprdataset(message, &qrdataset); + if (message != NULL) + dns_message_destroy(&message); + return (result); +} + +static isc_result_t +add_opt(dns_message_t *message, isc_uint16_t udpsize, isc_boolean_t reqnsid) { + dns_rdataset_t *rdataset = NULL; + dns_rdatalist_t *rdatalist = NULL; + dns_rdata_t *rdata = NULL; + isc_result_t result; + + result = dns_message_gettemprdatalist(message, &rdatalist); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_message_gettemprdata(message, &rdata); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_message_gettemprdataset(message, &rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_rdataset_init(rdataset); + + rdatalist->type = dns_rdatatype_opt; + rdatalist->covers = 0; + + /* + * Set Maximum UDP buffer size. + */ + rdatalist->rdclass = udpsize; + + /* + * Set EXTENDED-RCODE, VERSION, DO and Z to 0. + */ + rdatalist->ttl = 0; + + /* Set EDNS options if applicable */ + if (reqnsid) { + unsigned char data[4]; + isc_buffer_t buf; - zone_settimer(zone, &now); - UNLOCK_ZONE(zone); - goto free_stub; - } + isc_buffer_init(&buf, data, sizeof(data)); + isc_buffer_putuint16(&buf, DNS_OPT_NSID); + isc_buffer_putuint16(&buf, 0); + rdata->data = data; + rdata->length = sizeof(data); + } else { + rdata->data = NULL; + rdata->length = 0; } - queue_soa_query(zone); - UNLOCK_ZONE(zone); - goto free_stub; - same_master: - if (msg != NULL) - dns_message_destroy(&msg); - isc_event_free(&event); - LOCK_ZONE(zone); - dns_request_destroy(&zone->request); - UNLOCK_ZONE(zone); - ns_query(zone, NULL, stub); - goto done; + rdata->rdclass = rdatalist->rdclass; + rdata->type = rdatalist->type; + rdata->flags = 0; - free_stub: - stub->magic = 0; - dns_zone_idetach(&stub->zone); - INSIST(stub->db == NULL); - INSIST(stub->version == NULL); - isc_mem_put(stub->mctx, stub, sizeof(*stub)); + ISC_LIST_INIT(rdatalist->rdata); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) + == ISC_R_SUCCESS); - done: - INSIST(event == NULL); - return; + return (dns_message_setopt(message, rdataset)); + + cleanup: + if (rdatalist != NULL) + dns_message_puttemprdatalist(message, &rdatalist); + if (rdataset != NULL) + dns_message_puttemprdataset(message, &rdataset); + if (rdata != NULL) + dns_message_puttemprdata(message, &rdata); + + return (result); } -/* - * An SOA query has finished (successfully or not). - */ static void -refresh_callback(isc_task_t *task, isc_event_t *event) { - const char me[] = "refresh_callback"; - dns_requestevent_t *revent = (dns_requestevent_t *)event; - dns_zone_t *zone; - dns_message_t *msg = NULL; - isc_uint32_t soacnt, cnamecnt, soacount, nscount; - isc_time_t now; - char master[ISC_SOCKADDR_FORMATSIZE]; - char source[ISC_SOCKADDR_FORMATSIZE]; - dns_rdataset_t *rdataset = NULL; - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdata_soa_t soa; - isc_result_t result; - isc_uint32_t serial, oldserial; - unsigned int j; +soa_query(isc_task_t *task, isc_event_t *event) { + const char me[] = "soa_query"; + isc_result_t result = ISC_R_FAILURE; + dns_message_t *message = NULL; + dns_zone_t *zone = event->ev_arg; + dns_zone_t *dummy = NULL; + isc_netaddr_t masterip; + dns_tsigkey_t *key = NULL; + isc_uint32_t options; + isc_boolean_t cancel = ISC_TRUE; + int timeout; + isc_boolean_t have_xfrsource, reqnsid; + isc_uint16_t udpsize = SEND_BUFFER_SIZE; - zone = revent->ev_arg; - INSIST(DNS_ZONE_VALID(zone)); + REQUIRE(DNS_ZONE_VALID(zone)); UNUSED(task); ENTER; + LOCK_ZONE(zone); + if (((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0) || + DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) || + zone->view->requestmgr == NULL) { + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) + cancel = ISC_FALSE; + goto cleanup; + } + /* - * if timeout log and next master; + * XXX Optimisation: Create message when zone is setup and reuse. */ + result = create_query(zone, dns_rdatatype_soa, &message); + if (result != ISC_R_SUCCESS) + goto cleanup; - isc_sockaddr_format(&zone->masteraddr, master, sizeof(master)); - isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source)); + again: + INSIST(zone->masterscnt > 0); + INSIST(zone->curmaster < zone->masterscnt); - TIME_NOW(&now); + zone->masteraddr = zone->masters[zone->curmaster]; - if (revent->result != ISC_R_SUCCESS) { - if (revent->result == ISC_R_TIMEDOUT && - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { - LOCK_ZONE(zone); - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); - UNLOCK_ZONE(zone); - dns_zone_log(zone, ISC_LOG_DEBUG(1), - "refresh: timeout retrying without EDNS " - "master %s (source %s)", master, source); - goto same_master; + isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); + /* + * First, look for a tsig key in the master statement, then + * try for a server key. + */ + if ((zone->masterkeynames != NULL) && + (zone->masterkeynames[zone->curmaster] != NULL)) { + dns_view_t *view = dns_zone_getview(zone); + dns_name_t *keyname = zone->masterkeynames[zone->curmaster]; + result = dns_view_gettsig(view, keyname, &key); + if (result != ISC_R_SUCCESS) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(keyname, namebuf, sizeof(namebuf)); + dns_zone_log(zone, ISC_LOG_ERROR, + "unable to find key: %s", namebuf); + goto skip_master; } - if (revent->result == ISC_R_TIMEDOUT && - !dns_request_usedtcp(revent->request)) { - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: retry limit for " - "master %s exceeded (source %s)", - master, source); - /* Try with slave with TCP. */ - if (zone->type == dns_zone_slave && - DNS_ZONE_OPTION(zone, DNS_ZONEOPT_TRYTCPREFRESH)) { - if (!dns_zonemgr_unreachable(zone->zmgr, - &zone->masteraddr, - &zone->sourceaddr, - &now)) { - LOCK_ZONE(zone); - DNS_ZONE_SETFLAG(zone, - DNS_ZONEFLG_SOABEFOREAXFR); - UNLOCK_ZONE(zone); - goto tcp_transfer; - } - dns_zone_log(zone, ISC_LOG_DEBUG(1), - "refresh: skipped tcp fallback" - "as master %s (source %s) is " - "unreachable (cached)", - master, source); - } - } else - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: failure trying master " - "%s (source %s): %s", master, source, - dns_result_totext(revent->result)); - goto next_master; } + if (key == NULL) { + result = dns_view_getpeertsig(zone->view, &masterip, &key); + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { + char addrbuf[ISC_NETADDR_FORMATSIZE]; + isc_netaddr_format(&masterip, addrbuf, sizeof(addrbuf)); + dns_zone_log(zone, ISC_LOG_ERROR, + "unable to find TSIG key for %s", addrbuf); + goto skip_master; + } + } + + have_xfrsource = ISC_FALSE; + reqnsid = zone->view->requestnsid; + if (zone->view->peers != NULL) { + dns_peer_t *peer = NULL; + isc_boolean_t edns; + result = dns_peerlist_peerbyaddr(zone->view->peers, + &masterip, &peer); + if (result == ISC_R_SUCCESS) { + result = dns_peer_getsupportedns(peer, &edns); + if (result == ISC_R_SUCCESS && !edns) + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); + result = dns_peer_gettransfersource(peer, + &zone->sourceaddr); + if (result == ISC_R_SUCCESS) + have_xfrsource = ISC_TRUE; + if (zone->view->resolver != NULL) + udpsize = + dns_resolver_getudpsize(zone->view->resolver); + (void)dns_peer_getudpsize(peer, &udpsize); + (void)dns_peer_getrequestnsid(peer, &reqnsid); + } + } + + switch (isc_sockaddr_pf(&zone->masteraddr)) { + case PF_INET: + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { + if (isc_sockaddr_equal(&zone->altxfrsource4, + &zone->xfrsource4)) + goto skip_master; + zone->sourceaddr = zone->altxfrsource4; + } else if (!have_xfrsource) + zone->sourceaddr = zone->xfrsource4; + break; + case PF_INET6: + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { + if (isc_sockaddr_equal(&zone->altxfrsource6, + &zone->xfrsource6)) + goto skip_master; + zone->sourceaddr = zone->altxfrsource6; + } else if (!have_xfrsource) + zone->sourceaddr = zone->xfrsource6; + break; + default: + result = ISC_R_NOTIMPLEMENTED; + goto cleanup; + } + + options = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEVC) ? + DNS_REQUESTOPT_TCP : 0; + + if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { + result = add_opt(message, udpsize, reqnsid); + if (result != ISC_R_SUCCESS) + zone_debuglog(zone, me, 1, + "unable to add opt record: %s", + dns_result_totext(result)); + } + + zone_iattach(zone, &dummy); + timeout = 15; + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)) + timeout = 30; + result = dns_request_createvia2(zone->view->requestmgr, message, + &zone->sourceaddr, &zone->masteraddr, + options, key, timeout * 3, timeout, + zone->task, refresh_callback, zone, + &zone->request); + if (result != ISC_R_SUCCESS) { + zone_idetach(&dummy); + zone_debuglog(zone, me, 1, + "dns_request_createvia2() failed: %s", + dns_result_totext(result)); + goto cleanup; + } else { + if (isc_sockaddr_pf(&zone->masteraddr) == PF_INET) + inc_stats(zone, dns_zonestatscounter_soaoutv4); + else + inc_stats(zone, dns_zonestatscounter_soaoutv6); + } + cancel = ISC_FALSE; - result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTPARSE, &msg); + cleanup: + if (key != NULL) + dns_tsigkey_detach(&key); if (result != ISC_R_SUCCESS) - goto next_master; - result = dns_request_getresponse(revent->request, msg, 0); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: failure trying master " - "%s (source %s): %s", master, source, - dns_result_totext(result)); - goto next_master; - } + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); + if (message != NULL) + dns_message_destroy(&message); + if (cancel) + cancel_refresh(zone); + isc_event_free(&event); + UNLOCK_ZONE(zone); + dns_zone_idetach(&zone); + return; + skip_master: + if (key != NULL) + dns_tsigkey_detach(&key); /* - * Unexpected rcode. + * Skip to next failed / untried master. */ - if (msg->rcode != dns_rcode_noerror) { - char rcode[128]; - isc_buffer_t rb; + do { + zone->curmaster++; + } while (zone->curmaster < zone->masterscnt && + zone->mastersok[zone->curmaster]); + if (zone->curmaster < zone->masterscnt) + goto again; + zone->curmaster = 0; + goto cleanup; +} - isc_buffer_init(&rb, rcode, sizeof(rcode)); - (void)dns_rcode_totext(msg->rcode, &rb); +static void +ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) { + const char me[] = "ns_query"; + isc_result_t result; + dns_message_t *message = NULL; + isc_netaddr_t masterip; + dns_tsigkey_t *key = NULL; + dns_dbnode_t *node = NULL; + int timeout; + isc_boolean_t have_xfrsource = ISC_FALSE, reqnsid; + isc_uint16_t udpsize = SEND_BUFFER_SIZE; + + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE((soardataset != NULL && stub == NULL) || + (soardataset == NULL && stub != NULL)); + REQUIRE(stub == NULL || DNS_STUB_VALID(stub)); + + ENTER; + + LOCK_ZONE(zone); + if (stub == NULL) { + stub = isc_mem_get(zone->mctx, sizeof(*stub)); + if (stub == NULL) + goto cleanup; + stub->magic = STUB_MAGIC; + stub->mctx = zone->mctx; + stub->zone = NULL; + stub->db = NULL; + stub->version = NULL; - if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS) && - (msg->rcode == dns_rcode_servfail || - msg->rcode == dns_rcode_notimp || - msg->rcode == dns_rcode_formerr)) { - dns_zone_log(zone, ISC_LOG_DEBUG(1), - "refresh: rcode (%.*s) retrying without " - "EDNS master %s (source %s)", - (int)rb.used, rcode, master, source); - LOCK_ZONE(zone); - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); - UNLOCK_ZONE(zone); - goto same_master; - } - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: unexpected rcode (%.*s) from " - "master %s (source %s)", (int)rb.used, rcode, - master, source); /* - * Perhaps AXFR/IXFR is allowed even if SOA queries aren't. + * Attach so that the zone won't disappear from under us. */ - if (msg->rcode == dns_rcode_refused && - zone->type == dns_zone_slave) - goto tcp_transfer; - goto next_master; - } + zone_iattach(zone, &stub->zone); - /* - * If truncated punt to zone transfer which will query again. - */ - if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { - if (zone->type == dns_zone_slave) { - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: truncated UDP answer, " - "initiating TCP zone xfer " - "for master %s (source %s)", - master, source); - LOCK_ZONE(zone); - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR); - UNLOCK_ZONE(zone); - goto tcp_transfer; + /* + * If a db exists we will update it, otherwise we create a + * new one and attach it to the zone once we have the NS + * RRset and glue. + */ + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + if (zone->db != NULL) { + dns_db_attach(zone->db, &stub->db); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); } else { - INSIST(zone->type == dns_zone_stub); - if (dns_request_usedtcp(revent->request)) { - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: truncated TCP response " - "from master %s (source %s)", - master, source); - goto next_master; + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + + INSIST(zone->db_argc >= 1); + result = dns_db_create(zone->mctx, zone->db_argv[0], + &zone->origin, dns_dbtype_stub, + zone->rdclass, + zone->db_argc - 1, + zone->db_argv + 1, + &stub->db); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "refreshing stub: " + "could not create " + "database: %s", + dns_result_totext(result)); + goto cleanup; } - LOCK_ZONE(zone); - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEVC); - UNLOCK_ZONE(zone); - goto same_master; + dns_db_settask(stub->db, zone->task); + } + + dns_db_newversion(stub->db, &stub->version); + + /* + * Update SOA record. + */ + result = dns_db_findnode(stub->db, &zone->origin, ISC_TRUE, + &node); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_INFO, + "refreshing stub: " + "dns_db_findnode() failed: %s", + dns_result_totext(result)); + goto cleanup; + } + + result = dns_db_addrdataset(stub->db, node, stub->version, 0, + soardataset, 0, NULL); + dns_db_detachnode(stub->db, &node); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_INFO, + "refreshing stub: " + "dns_db_addrdataset() failed: %s", + dns_result_totext(result)); + goto cleanup; } } /* - * if non-auth log and next master; + * XXX Optimisation: Create message when zone is setup and reuse. */ - if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) { - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: non-authoritative answer from " - "master %s (source %s)", master, source); - goto next_master; - } + result = create_query(zone, dns_rdatatype_ns, &message); - cnamecnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_cname); - soacnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_soa); - nscount = message_count(msg, DNS_SECTION_AUTHORITY, dns_rdatatype_ns); - soacount = message_count(msg, DNS_SECTION_AUTHORITY, - dns_rdatatype_soa); + INSIST(zone->masterscnt > 0); + INSIST(zone->curmaster < zone->masterscnt); + zone->masteraddr = zone->masters[zone->curmaster]; + isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); /* - * There should not be a CNAME record at top of zone. + * First, look for a tsig key in the master statement, then + * try for a server key. */ - if (cnamecnt != 0) { - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: CNAME at top of zone " - "in master %s (source %s)", master, source); - goto next_master; + if ((zone->masterkeynames != NULL) && + (zone->masterkeynames[zone->curmaster] != NULL)) { + dns_view_t *view = dns_zone_getview(zone); + dns_name_t *keyname = zone->masterkeynames[zone->curmaster]; + result = dns_view_gettsig(view, keyname, &key); + if (result != ISC_R_SUCCESS) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(keyname, namebuf, sizeof(namebuf)); + dns_zone_log(zone, ISC_LOG_ERROR, + "unable to find key: %s", namebuf); + } } + if (key == NULL) + (void)dns_view_getpeertsig(zone->view, &masterip, &key); - /* - * if referral log and next master; - */ - if (soacnt == 0 && soacount == 0 && nscount != 0) { - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: referral response " - "from master %s (source %s)", master, source); - goto next_master; - } + reqnsid = zone->view->requestnsid; + if (zone->view->peers != NULL) { + dns_peer_t *peer = NULL; + isc_boolean_t edns; + result = dns_peerlist_peerbyaddr(zone->view->peers, + &masterip, &peer); + if (result == ISC_R_SUCCESS) { + result = dns_peer_getsupportedns(peer, &edns); + if (result == ISC_R_SUCCESS && !edns) + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); + result = dns_peer_gettransfersource(peer, + &zone->sourceaddr); + if (result == ISC_R_SUCCESS) + have_xfrsource = ISC_TRUE; + if (zone->view->resolver != NULL) + udpsize = + dns_resolver_getudpsize(zone->view->resolver); + (void)dns_peer_getudpsize(peer, &udpsize); + (void)dns_peer_getrequestnsid(peer, &reqnsid); + } - /* - * if nodata log and next master; - */ - if (soacnt == 0 && (nscount == 0 || soacount != 0)) { - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: NODATA response " - "from master %s (source %s)", master, source); - goto next_master; + } + if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { + result = add_opt(message, udpsize, reqnsid); + if (result != ISC_R_SUCCESS) + zone_debuglog(zone, me, 1, + "unable to add opt record: %s", + dns_result_totext(result)); } /* - * Only one soa at top of zone. + * Always use TCP so that we shouldn't truncate in additional section. */ - if (soacnt != 1) { - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: answer SOA count (%d) != 1 " - "from master %s (source %s)", - soacnt, master, source); - goto next_master; + switch (isc_sockaddr_pf(&zone->masteraddr)) { + case PF_INET: + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) + zone->sourceaddr = zone->altxfrsource4; + else if (!have_xfrsource) + zone->sourceaddr = zone->xfrsource4; + break; + case PF_INET6: + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) + zone->sourceaddr = zone->altxfrsource6; + else if (!have_xfrsource) + zone->sourceaddr = zone->xfrsource6; + break; + default: + result = ISC_R_NOTIMPLEMENTED; + goto cleanup; } - /* - * Extract serial - */ - rdataset = NULL; - result = dns_message_findname(msg, DNS_SECTION_ANSWER, &zone->origin, - dns_rdatatype_soa, dns_rdatatype_none, - NULL, &rdataset); + timeout = 15; + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)) + timeout = 30; + result = dns_request_createvia2(zone->view->requestmgr, message, + &zone->sourceaddr, &zone->masteraddr, + DNS_REQUESTOPT_TCP, key, timeout * 3, + timeout, zone->task, stub_callback, + stub, &zone->request); if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: unable to get SOA record " - "from master %s (source %s)", master, source); - goto next_master; + zone_debuglog(zone, me, 1, + "dns_request_createvia() failed: %s", + dns_result_totext(result)); + goto cleanup; } + dns_message_destroy(&message); + goto unlock; - result = dns_rdataset_first(rdataset); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: dns_rdataset_first() failed"); - goto next_master; + cleanup: + cancel_refresh(zone); + if (stub != NULL) { + stub->magic = 0; + if (stub->version != NULL) + dns_db_closeversion(stub->db, &stub->version, + ISC_FALSE); + if (stub->db != NULL) + dns_db_detach(&stub->db); + if (stub->zone != NULL) + zone_idetach(&stub->zone); + isc_mem_put(stub->mctx, stub, sizeof(*stub)); } + if (message != NULL) + dns_message_destroy(&message); + unlock: + if (key != NULL) + dns_tsigkey_detach(&key); + UNLOCK_ZONE(zone); + return; +} - dns_rdataset_current(rdataset, &rdata); - result = dns_rdata_tostruct(&rdata, &soa, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); +/* + * Handle the control event. Note that although this event causes the zone + * to shut down, it is not a shutdown event in the sense of the task library. + */ +static void +zone_shutdown(isc_task_t *task, isc_event_t *event) { + dns_zone_t *zone = (dns_zone_t *) event->ev_arg; + isc_boolean_t free_needed, linked = ISC_FALSE; - serial = soa.serial; - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) { - result = dns_zone_getserial2(zone, &oldserial); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - zone_debuglog(zone, me, 1, "serial: new %u, old %u", - serial, oldserial); - } else - zone_debuglog(zone, me, 1, "serial: new %u, old not loaded", - serial); - if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) || - DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER) || - isc_serial_gt(serial, oldserial)) { - if (dns_zonemgr_unreachable(zone->zmgr, &zone->masteraddr, - &zone->sourceaddr, &now)) { - dns_zone_log(zone, ISC_LOG_INFO, - "refresh: skipping %s as master %s " - "(source %s) is unreachable (cached)", - zone->type == dns_zone_slave ? - "zone transfer" : "NS query", - master, source); - goto next_master; - } - tcp_transfer: - isc_event_free(&event); - LOCK_ZONE(zone); - dns_request_destroy(&zone->request); - UNLOCK_ZONE(zone); - if (zone->type == dns_zone_slave) { - queue_xfrin(zone); - } else { - INSIST(zone->type == dns_zone_stub); - ns_query(zone, rdataset, NULL); - } - if (msg != NULL) - dns_message_destroy(&msg); - } else if (isc_serial_eq(soa.serial, oldserial)) { - if (zone->masterfile != NULL) { - result = ISC_R_FAILURE; - if (zone->journal != NULL) - result = isc_file_settime(zone->journal, &now); - if (result == ISC_R_SUCCESS && - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { - result = isc_file_settime(zone->masterfile, - &now); - } else if (result != ISC_R_SUCCESS) - result = isc_file_settime(zone->masterfile, - &now); - /* Someone removed the file from underneath us! */ - if (result == ISC_R_FILENOTFOUND) { - LOCK_ZONE(zone); - zone_needdump(zone, DNS_DUMP_DELAY); - UNLOCK_ZONE(zone); - } else if (result != ISC_R_SUCCESS) - dns_zone_log(zone, ISC_LOG_ERROR, - "refresh: could not set file " - "modification time of '%s': %s", - zone->masterfile, - dns_result_totext(result)); - } - DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime); - DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime); - zone->mastersok[zone->curmaster] = ISC_TRUE; - goto next_master; - } else { - if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MULTIMASTER)) - dns_zone_log(zone, ISC_LOG_INFO, "serial number (%u) " - "received from master %s < ours (%u)", - soa.serial, master, oldserial); - else - zone_debuglog(zone, me, 1, "ahead"); - zone->mastersok[zone->curmaster] = ISC_TRUE; - goto next_master; - } - if (msg != NULL) - dns_message_destroy(&msg); - goto detach; + UNUSED(task); + REQUIRE(DNS_ZONE_VALID(zone)); + INSIST(event->ev_type == DNS_EVENT_ZONECONTROL); + INSIST(isc_refcount_current(&zone->erefs) == 0); + zone_debuglog(zone, "zone_shutdown", 3, "shutting down"); - next_master: - if (msg != NULL) - dns_message_destroy(&msg); - isc_event_free(&event); - LOCK_ZONE(zone); - dns_request_destroy(&zone->request); /* - * Skip to next failed / untried master. + * Stop things being restarted after we cancel them below. */ - do { - zone->curmaster++; - } while (zone->curmaster < zone->masterscnt && - zone->mastersok[zone->curmaster]); - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS); - if (zone->curmaster >= zone->masterscnt) { - isc_boolean_t done = ISC_TRUE; - if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) && - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { - /* - * Did we get a good answer from all the masters? - */ - for (j = 0; j < zone->masterscnt; j++) - if (zone->mastersok[j] == ISC_FALSE) { - done = ISC_FALSE; - break; - } - } else - done = ISC_TRUE; - if (!done) { - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); - zone->curmaster = 0; - /* - * Find the next failed master. - */ - while (zone->curmaster < zone->masterscnt && - zone->mastersok[zone->curmaster]) - zone->curmaster++; - goto requeue; - } - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDREFRESH)) { - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDREFRESH); - zone->refreshtime = now; - } - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); - zone_settimer(zone, &now); - UNLOCK_ZONE(zone); - goto detach; - } - - requeue: - queue_soa_query(zone); - UNLOCK_ZONE(zone); - goto detach; - - same_master: - if (msg != NULL) - dns_message_destroy(&msg); - isc_event_free(&event); LOCK_ZONE(zone); - dns_request_destroy(&zone->request); - queue_soa_query(zone); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_EXITING); UNLOCK_ZONE(zone); - detach: - dns_zone_idetach(&zone); - return; -} - -static void -queue_soa_query(dns_zone_t *zone) { - const char me[] = "queue_soa_query"; - isc_event_t *e; - dns_zone_t *dummy = NULL; - isc_result_t result; + /* + * If we were waiting for xfrin quota, step out of + * the queue. + * If there's no zone manager, we can't be waiting for the + * xfrin quota + */ + if (zone->zmgr != NULL) { + RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); + if (zone->statelist == &zone->zmgr->waiting_for_xfrin) { + ISC_LIST_UNLINK(zone->zmgr->waiting_for_xfrin, zone, + statelink); + linked = ISC_TRUE; + zone->statelist = NULL; + } + RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); + } - ENTER; /* - * Locked by caller + * In task context, no locking required. See zone_xfrdone(). */ - REQUIRE(LOCKED_ZONE(zone)); + if (zone->xfr != NULL) + dns_xfrin_shutdown(zone->xfr); - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { - cancel_refresh(zone); - return; + LOCK_ZONE(zone); + if (linked) { + INSIST(zone->irefs > 0); + zone->irefs--; } - - e = isc_event_allocate(zone->mctx, NULL, DNS_EVENT_ZONE, - soa_query, zone, sizeof(isc_event_t)); - if (e == NULL) { - cancel_refresh(zone); - return; + if (zone->request != NULL) { + dns_request_cancel(zone->request); } - /* - * Attach so that we won't clean up - * until the event is delivered. - */ - zone_iattach(zone, &dummy); + if (zone->readio != NULL) + zonemgr_cancelio(zone->readio); - e->ev_arg = zone; - e->ev_sender = NULL; - result = isc_ratelimiter_enqueue(zone->zmgr->rl, zone->task, &e); - if (result != ISC_R_SUCCESS) { - zone_idetach(&dummy); - isc_event_free(&e); - cancel_refresh(zone); - } -} + if (zone->lctx != NULL) + dns_loadctx_cancel(zone->lctx); -static inline isc_result_t -create_query(dns_zone_t *zone, dns_rdatatype_t rdtype, - dns_message_t **messagep) -{ - dns_message_t *message = NULL; - dns_name_t *qname = NULL; - dns_rdataset_t *qrdataset = NULL; - isc_result_t result; + if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FLUSH) || + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { + if (zone->writeio != NULL) + zonemgr_cancelio(zone->writeio); - result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTRENDER, - &message); - if (result != ISC_R_SUCCESS) - goto cleanup; + if (zone->dctx != NULL) + dns_dumpctx_cancel(zone->dctx); + } - message->opcode = dns_opcode_query; - message->rdclass = zone->rdclass; + notify_cancel(zone); - result = dns_message_gettempname(message, &qname); - if (result != ISC_R_SUCCESS) - goto cleanup; + if (zone->timer != NULL) { + isc_timer_detach(&zone->timer); + INSIST(zone->irefs > 0); + zone->irefs--; + } - result = dns_message_gettemprdataset(message, &qrdataset); - if (result != ISC_R_SUCCESS) - goto cleanup; + if (zone->view != NULL) + dns_view_weakdetach(&zone->view); /* - * Make question. + * We have now canceled everything set the flag to allow exit_check() + * to succeed. We must not unlock between setting this flag and + * calling exit_check(). */ - dns_name_init(qname, NULL); - dns_name_clone(&zone->origin, qname); - dns_rdataset_init(qrdataset); - dns_rdataset_makequestion(qrdataset, zone->rdclass, rdtype); - ISC_LIST_APPEND(qname->list, qrdataset, link); - dns_message_addname(message, qname, DNS_SECTION_QUESTION); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SHUTDOWN); + free_needed = exit_check(zone); + UNLOCK_ZONE(zone); + if (free_needed) + zone_free(zone); +} - *messagep = message; - return (ISC_R_SUCCESS); +static void +zone_timer(isc_task_t *task, isc_event_t *event) { + const char me[] = "zone_timer"; + dns_zone_t *zone = (dns_zone_t *)event->ev_arg; - cleanup: - if (qname != NULL) - dns_message_puttempname(message, &qname); - if (qrdataset != NULL) - dns_message_puttemprdataset(message, &qrdataset); - if (message != NULL) - dns_message_destroy(&message); - return (result); + UNUSED(task); + REQUIRE(DNS_ZONE_VALID(zone)); + + ENTER; + + zone_maintenance(zone); + + isc_event_free(&event); } -static isc_result_t -add_opt(dns_message_t *message, isc_uint16_t udpsize, isc_boolean_t reqnsid) { - dns_rdataset_t *rdataset = NULL; - dns_rdatalist_t *rdatalist = NULL; - dns_rdata_t *rdata = NULL; +static void +zone_settimer(dns_zone_t *zone, isc_time_t *now) { + const char me[] = "zone_settimer"; + isc_time_t next; isc_result_t result; - result = dns_message_gettemprdatalist(message, &rdatalist); - if (result != ISC_R_SUCCESS) - goto cleanup; - result = dns_message_gettemprdata(message, &rdata); - if (result != ISC_R_SUCCESS) - goto cleanup; - result = dns_message_gettemprdataset(message, &rdataset); - if (result != ISC_R_SUCCESS) - goto cleanup; - dns_rdataset_init(rdataset); + ENTER; + REQUIRE(DNS_ZONE_VALID(zone)); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) + return; - rdatalist->type = dns_rdatatype_opt; - rdatalist->covers = 0; + isc_time_settoepoch(&next); - /* - * Set Maximum UDP buffer size. - */ - rdatalist->rdclass = udpsize; + switch (zone->type) { + case dns_zone_master: + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY)) + next = zone->notifytime; + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { + INSIST(!isc_time_isepoch(&zone->dumptime)); + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->dumptime, &next) < 0) + next = zone->dumptime; + } + if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING) && + !isc_time_isepoch(&zone->refreshkeytime)) { + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->refreshkeytime, &next) < 0) + next = zone->refreshkeytime; + } + if (!isc_time_isepoch(&zone->resigntime)) { + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->resigntime, &next) < 0) + next = zone->resigntime; + } + if (!isc_time_isepoch(&zone->keywarntime)) { + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->keywarntime, &next) < 0) + next = zone->keywarntime; + } + if (!isc_time_isepoch(&zone->signingtime)) { + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->signingtime, &next) < 0) + next = zone->signingtime; + } + if (!isc_time_isepoch(&zone->nsec3chaintime)) { + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->nsec3chaintime, &next) < 0) + next = zone->nsec3chaintime; + } + break; - /* - * Set EXTENDED-RCODE, VERSION, DO and Z to 0. - */ - rdatalist->ttl = 0; + case dns_zone_slave: + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY)) + next = zone->notifytime; + /*FALLTHROUGH*/ - /* Set EDNS options if applicable */ - if (reqnsid) { - unsigned char data[4]; - isc_buffer_t buf; + case dns_zone_stub: + if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOMASTERS) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOREFRESH) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADING)) { + INSIST(!isc_time_isepoch(&zone->refreshtime)); + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->refreshtime, &next) < 0) + next = zone->refreshtime; + } + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) { + INSIST(!isc_time_isepoch(&zone->expiretime)); + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->expiretime, &next) < 0) + next = zone->expiretime; + } + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { + INSIST(!isc_time_isepoch(&zone->dumptime)); + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->dumptime, &next) < 0) + next = zone->dumptime; + } + break; - isc_buffer_init(&buf, data, sizeof(data)); - isc_buffer_putuint16(&buf, DNS_OPT_NSID); - isc_buffer_putuint16(&buf, 0); - rdata->data = data; - rdata->length = sizeof(data); + case dns_zone_key: + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { + INSIST(!isc_time_isepoch(&zone->dumptime)); + if (isc_time_isepoch(&next) || + isc_time_compare(&zone->dumptime, &next) < 0) + next = zone->dumptime; + } + if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING)) { + if (isc_time_isepoch(&next) || + (!isc_time_isepoch(&zone->refreshkeytime) && + isc_time_compare(&zone->refreshkeytime, &next) < 0)) + next = zone->refreshkeytime; + } + break; + + default: + break; + } + + if (isc_time_isepoch(&next)) { + zone_debuglog(zone, me, 10, "settimer inactive"); + result = isc_timer_reset(zone->timer, isc_timertype_inactive, + NULL, NULL, ISC_TRUE); + if (result != ISC_R_SUCCESS) + dns_zone_log(zone, ISC_LOG_ERROR, + "could not deactivate zone timer: %s", + isc_result_totext(result)); } else { - rdata->data = NULL; - rdata->length = 0; + if (isc_time_compare(&next, now) <= 0) + next = *now; + result = isc_timer_reset(zone->timer, isc_timertype_once, + &next, NULL, ISC_TRUE); + if (result != ISC_R_SUCCESS) + dns_zone_log(zone, ISC_LOG_ERROR, + "could not reset zone timer: %s", + isc_result_totext(result)); } +} - rdata->rdclass = rdatalist->rdclass; - rdata->type = rdatalist->type; - rdata->flags = 0; +static void +cancel_refresh(dns_zone_t *zone) { + const char me[] = "cancel_refresh"; + isc_time_t now; - ISC_LIST_INIT(rdatalist->rdata); - ISC_LIST_APPEND(rdatalist->rdata, rdata, link); - RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) - == ISC_R_SUCCESS); + /* + * 'zone' locked by caller. + */ - return (dns_message_setopt(message, rdataset)); + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(LOCKED_ZONE(zone)); - cleanup: - if (rdatalist != NULL) - dns_message_puttemprdatalist(message, &rdatalist); - if (rdataset != NULL) - dns_message_puttemprdataset(message, &rdataset); - if (rdata != NULL) - dns_message_puttemprdata(message, &rdata); + ENTER; - return (result); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); + TIME_NOW(&now); + zone_settimer(zone, &now); } -static void -soa_query(isc_task_t *task, isc_event_t *event) { - const char me[] = "soa_query"; - isc_result_t result = ISC_R_FAILURE; +static isc_result_t +notify_createmessage(dns_zone_t *zone, unsigned int flags, + dns_message_t **messagep) +{ + dns_db_t *zonedb = NULL; + dns_dbnode_t *node = NULL; + dns_dbversion_t *version = NULL; dns_message_t *message = NULL; - dns_zone_t *zone = event->ev_arg; - dns_zone_t *dummy = NULL; - isc_netaddr_t masterip; - dns_tsigkey_t *key = NULL; - isc_uint32_t options; - isc_boolean_t cancel = ISC_TRUE; - int timeout; - isc_boolean_t have_xfrsource, reqnsid; - isc_uint16_t udpsize = SEND_BUFFER_SIZE; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_name_t *tempname = NULL; + dns_rdata_t *temprdata = NULL; + dns_rdatalist_t *temprdatalist = NULL; + dns_rdataset_t *temprdataset = NULL; + + isc_result_t result; + isc_region_t r; + isc_buffer_t *b = NULL; REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(messagep != NULL && *messagep == NULL); - UNUSED(task); + result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTRENDER, + &message); + if (result != ISC_R_SUCCESS) + return (result); - ENTER; + message->opcode = dns_opcode_notify; + message->flags |= DNS_MESSAGEFLAG_AA; + message->rdclass = zone->rdclass; - LOCK_ZONE(zone); - if (((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0) || - DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) || - zone->view->requestmgr == NULL) { - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) - cancel = ISC_FALSE; + result = dns_message_gettempname(message, &tempname); + if (result != ISC_R_SUCCESS) goto cleanup; - } - /* - * XXX Optimisation: Create message when zone is setup and reuse. - */ - result = create_query(zone, dns_rdatatype_soa, &message); + result = dns_message_gettemprdataset(message, &temprdataset); if (result != ISC_R_SUCCESS) goto cleanup; - again: - INSIST(zone->masterscnt > 0); - INSIST(zone->curmaster < zone->masterscnt); - - zone->masteraddr = zone->masters[zone->curmaster]; - - isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); /* - * First, look for a tsig key in the master statement, then - * try for a server key. + * Make question. */ - if ((zone->masterkeynames != NULL) && - (zone->masterkeynames[zone->curmaster] != NULL)) { - dns_view_t *view = dns_zone_getview(zone); - dns_name_t *keyname = zone->masterkeynames[zone->curmaster]; - result = dns_view_gettsig(view, keyname, &key); - if (result != ISC_R_SUCCESS) { - char namebuf[DNS_NAME_FORMATSIZE]; - dns_name_format(keyname, namebuf, sizeof(namebuf)); - dns_zone_log(zone, ISC_LOG_ERROR, - "unable to find key: %s", namebuf); - goto skip_master; - } - } - if (key == NULL) { - result = dns_view_getpeertsig(zone->view, &masterip, &key); - if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { - char addrbuf[ISC_NETADDR_FORMATSIZE]; - isc_netaddr_format(&masterip, addrbuf, sizeof(addrbuf)); - dns_zone_log(zone, ISC_LOG_ERROR, - "unable to find TSIG key for %s", addrbuf); - goto skip_master; - } - } + dns_name_init(tempname, NULL); + dns_name_clone(&zone->origin, tempname); + dns_rdataset_init(temprdataset); + dns_rdataset_makequestion(temprdataset, zone->rdclass, + dns_rdatatype_soa); + ISC_LIST_APPEND(tempname->list, temprdataset, link); + dns_message_addname(message, tempname, DNS_SECTION_QUESTION); + tempname = NULL; + temprdataset = NULL; - have_xfrsource = ISC_FALSE; - reqnsid = zone->view->requestnsid; - if (zone->view->peers != NULL) { - dns_peer_t *peer = NULL; - isc_boolean_t edns; - result = dns_peerlist_peerbyaddr(zone->view->peers, - &masterip, &peer); - if (result == ISC_R_SUCCESS) { - result = dns_peer_getsupportedns(peer, &edns); - if (result == ISC_R_SUCCESS && !edns) - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); - result = dns_peer_gettransfersource(peer, - &zone->sourceaddr); - if (result == ISC_R_SUCCESS) - have_xfrsource = ISC_TRUE; - if (zone->view->resolver != NULL) - udpsize = - dns_resolver_getudpsize(zone->view->resolver); - (void)dns_peer_getudpsize(peer, &udpsize); - (void)dns_peer_getrequestnsid(peer, &reqnsid); - } - } + if ((flags & DNS_NOTIFY_NOSOA) != 0) + goto done; - switch (isc_sockaddr_pf(&zone->masteraddr)) { - case PF_INET: - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { - if (isc_sockaddr_equal(&zone->altxfrsource4, - &zone->xfrsource4)) - goto skip_master; - zone->sourceaddr = zone->altxfrsource4; - } else if (!have_xfrsource) - zone->sourceaddr = zone->xfrsource4; - break; - case PF_INET6: - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { - if (isc_sockaddr_equal(&zone->altxfrsource6, - &zone->xfrsource6)) - goto skip_master; - zone->sourceaddr = zone->altxfrsource6; - } else if (!have_xfrsource) - zone->sourceaddr = zone->xfrsource6; - break; - default: - result = ISC_R_NOTIMPLEMENTED; - goto cleanup; - } + result = dns_message_gettempname(message, &tempname); + if (result != ISC_R_SUCCESS) + goto soa_cleanup; + result = dns_message_gettemprdata(message, &temprdata); + if (result != ISC_R_SUCCESS) + goto soa_cleanup; + result = dns_message_gettemprdataset(message, &temprdataset); + if (result != ISC_R_SUCCESS) + goto soa_cleanup; + result = dns_message_gettemprdatalist(message, &temprdatalist); + if (result != ISC_R_SUCCESS) + goto soa_cleanup; - options = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEVC) ? - DNS_REQUESTOPT_TCP : 0; + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + INSIST(zone->db != NULL); /* XXXJT: is this assumption correct? */ + dns_db_attach(zone->db, &zonedb); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); - if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { - result = add_opt(message, udpsize, reqnsid); - if (result != ISC_R_SUCCESS) - zone_debuglog(zone, me, 1, - "unable to add opt record: %s", - dns_result_totext(result)); - } + dns_name_init(tempname, NULL); + dns_name_clone(&zone->origin, tempname); + dns_db_currentversion(zonedb, &version); + result = dns_db_findnode(zonedb, tempname, ISC_FALSE, &node); + if (result != ISC_R_SUCCESS) + goto soa_cleanup; + + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(zonedb, node, version, + dns_rdatatype_soa, + dns_rdatatype_none, 0, &rdataset, + NULL); + if (result != ISC_R_SUCCESS) + goto soa_cleanup; + result = dns_rdataset_first(&rdataset); + if (result != ISC_R_SUCCESS) + goto soa_cleanup; + dns_rdataset_current(&rdataset, &rdata); + dns_rdata_toregion(&rdata, &r); + result = isc_buffer_allocate(zone->mctx, &b, r.length); + if (result != ISC_R_SUCCESS) + goto soa_cleanup; + isc_buffer_putmem(b, r.base, r.length); + isc_buffer_usedregion(b, &r); + dns_rdata_init(temprdata); + dns_rdata_fromregion(temprdata, rdata.rdclass, rdata.type, &r); + dns_message_takebuffer(message, &b); + result = dns_rdataset_next(&rdataset); + dns_rdataset_disassociate(&rdataset); + if (result != ISC_R_NOMORE) + goto soa_cleanup; + temprdatalist->rdclass = rdata.rdclass; + temprdatalist->type = rdata.type; + temprdatalist->covers = 0; + temprdatalist->ttl = rdataset.ttl; + ISC_LIST_INIT(temprdatalist->rdata); + ISC_LIST_APPEND(temprdatalist->rdata, temprdata, link); + + dns_rdataset_init(temprdataset); + result = dns_rdatalist_tordataset(temprdatalist, temprdataset); + if (result != ISC_R_SUCCESS) + goto soa_cleanup; + + ISC_LIST_APPEND(tempname->list, temprdataset, link); + dns_message_addname(message, tempname, DNS_SECTION_ANSWER); + temprdatalist = NULL; + temprdataset = NULL; + temprdata = NULL; + tempname = NULL; + + soa_cleanup: + if (node != NULL) + dns_db_detachnode(zonedb, &node); + if (version != NULL) + dns_db_closeversion(zonedb, &version, ISC_FALSE); + if (zonedb != NULL) + dns_db_detach(&zonedb); + if (tempname != NULL) + dns_message_puttempname(message, &tempname); + if (temprdata != NULL) + dns_message_puttemprdata(message, &temprdata); + if (temprdataset != NULL) + dns_message_puttemprdataset(message, &temprdataset); + if (temprdatalist != NULL) + dns_message_puttemprdatalist(message, &temprdatalist); - zone_iattach(zone, &dummy); - timeout = 15; - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)) - timeout = 30; - result = dns_request_createvia2(zone->view->requestmgr, message, - &zone->sourceaddr, &zone->masteraddr, - options, key, timeout * 3, timeout, - zone->task, refresh_callback, zone, - &zone->request); - if (result != ISC_R_SUCCESS) { - zone_idetach(&dummy); - zone_debuglog(zone, me, 1, - "dns_request_createvia2() failed: %s", - dns_result_totext(result)); - goto cleanup; - } else { - if (isc_sockaddr_pf(&zone->masteraddr) == PF_INET) - inc_stats(zone, dns_zonestatscounter_soaoutv4); - else - inc_stats(zone, dns_zonestatscounter_soaoutv6); - } - cancel = ISC_FALSE; + done: + *messagep = message; + return (ISC_R_SUCCESS); cleanup: - if (key != NULL) - dns_tsigkey_detach(&key); - if (result != ISC_R_SUCCESS) - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); - if (message != NULL) - dns_message_destroy(&message); - if (cancel) - cancel_refresh(zone); - isc_event_free(&event); - UNLOCK_ZONE(zone); - dns_zone_idetach(&zone); - return; - - skip_master: - if (key != NULL) - dns_tsigkey_detach(&key); - /* - * Skip to next failed / untried master. - */ - do { - zone->curmaster++; - } while (zone->curmaster < zone->masterscnt && - zone->mastersok[zone->curmaster]); - if (zone->curmaster < zone->masterscnt) - goto again; - zone->curmaster = 0; - goto cleanup; + if (tempname != NULL) + dns_message_puttempname(message, &tempname); + if (temprdataset != NULL) + dns_message_puttemprdataset(message, &temprdataset); + dns_message_destroy(&message); + return (result); } -static void -ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) { - const char me[] = "ns_query"; +isc_result_t +dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, + dns_message_t *msg) +{ + unsigned int i; + dns_rdata_soa_t soa; + dns_rdataset_t *rdataset = NULL; + dns_rdata_t rdata = DNS_RDATA_INIT; isc_result_t result; - dns_message_t *message = NULL; - isc_netaddr_t masterip; - dns_tsigkey_t *key = NULL; - dns_dbnode_t *node = NULL; - int timeout; - isc_boolean_t have_xfrsource = ISC_FALSE, reqnsid; - isc_uint16_t udpsize = SEND_BUFFER_SIZE; + char fromtext[ISC_SOCKADDR_FORMATSIZE]; + int match = 0; + isc_netaddr_t netaddr; REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE((soardataset != NULL && stub == NULL) || - (soardataset == NULL && stub != NULL)); - REQUIRE(stub == NULL || DNS_STUB_VALID(stub)); - ENTER; + /* + * If type != T_SOA return DNS_R_NOTIMP. We don't yet support + * ROLLOVER. + * + * SOA: RFC1996 + * Check that 'from' is a valid notify source, (zone->masters). + * Return DNS_R_REFUSED if not. + * + * If the notify message contains a serial number check it + * against the zones serial and return if <= current serial + * + * If a refresh check is progress, if so just record the + * fact we received a NOTIFY and from where and return. + * We will perform a new refresh check when the current one + * completes. Return ISC_R_SUCCESS. + * + * Otherwise initiate a refresh check using 'from' as the + * first address to check. Return ISC_R_SUCCESS. + */ - LOCK_ZONE(zone); - if (stub == NULL) { - stub = isc_mem_get(zone->mctx, sizeof(*stub)); - if (stub == NULL) - goto cleanup; - stub->magic = STUB_MAGIC; - stub->mctx = zone->mctx; - stub->zone = NULL; - stub->db = NULL; - stub->version = NULL; + isc_sockaddr_format(from, fromtext, sizeof(fromtext)); - /* - * Attach so that the zone won't disappear from under us. - */ - zone_iattach(zone, &stub->zone); + /* + * We only handle NOTIFY (SOA) at the present. + */ + LOCK_ZONE(zone); + if (isc_sockaddr_pf(from) == PF_INET) + inc_stats(zone, dns_zonestatscounter_notifyinv4); + else + inc_stats(zone, dns_zonestatscounter_notifyinv6); + if (msg->counts[DNS_SECTION_QUESTION] == 0 || + dns_message_findname(msg, DNS_SECTION_QUESTION, &zone->origin, + dns_rdatatype_soa, dns_rdatatype_none, + NULL, NULL) != ISC_R_SUCCESS) { + UNLOCK_ZONE(zone); + if (msg->counts[DNS_SECTION_QUESTION] == 0) { + dns_zone_log(zone, ISC_LOG_NOTICE, + "NOTIFY with no " + "question section from: %s", fromtext); + return (DNS_R_FORMERR); + } + dns_zone_log(zone, ISC_LOG_NOTICE, + "NOTIFY zone does not match"); + return (DNS_R_NOTIMP); + } - /* - * If a db exists we will update it, otherwise we create a - * new one and attach it to the zone once we have the NS - * RRset and glue. - */ - ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); - if (zone->db != NULL) { - dns_db_attach(zone->db, &stub->db); - ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); - } else { - ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + /* + * If we are a master zone just succeed. + */ + if (zone->type == dns_zone_master) { + UNLOCK_ZONE(zone); + return (ISC_R_SUCCESS); + } - INSIST(zone->db_argc >= 1); - result = dns_db_create(zone->mctx, zone->db_argv[0], - &zone->origin, dns_dbtype_stub, - zone->rdclass, - zone->db_argc - 1, - zone->db_argv + 1, - &stub->db); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "refreshing stub: " - "could not create " - "database: %s", - dns_result_totext(result)); - goto cleanup; - } - dns_db_settask(stub->db, zone->task); + isc_netaddr_fromsockaddr(&netaddr, from); + for (i = 0; i < zone->masterscnt; i++) { + if (isc_sockaddr_eqaddr(from, &zone->masters[i])) + break; + if (zone->view->aclenv.match_mapped && + IN6_IS_ADDR_V4MAPPED(&from->type.sin6.sin6_addr) && + isc_sockaddr_pf(&zone->masters[i]) == AF_INET) { + isc_netaddr_t na1, na2; + isc_netaddr_fromv4mapped(&na1, &netaddr); + isc_netaddr_fromsockaddr(&na2, &zone->masters[i]); + if (isc_netaddr_equal(&na1, &na2)) + break; } + } - dns_db_newversion(stub->db, &stub->version); + /* + * Accept notify requests from non masters if they are on + * 'zone->notify_acl'. + */ + if (i >= zone->masterscnt && zone->notify_acl != NULL && + dns_acl_match(&netaddr, NULL, zone->notify_acl, + &zone->view->aclenv, + &match, NULL) == ISC_R_SUCCESS && + match > 0) + { + /* Accept notify. */ + } else if (i >= zone->masterscnt) { + UNLOCK_ZONE(zone); + dns_zone_log(zone, ISC_LOG_INFO, + "refused notify from non-master: %s", fromtext); + inc_stats(zone, dns_zonestatscounter_notifyrej); + return (DNS_R_REFUSED); + } - /* - * Update SOA record. - */ - result = dns_db_findnode(stub->db, &zone->origin, ISC_TRUE, - &node); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_INFO, - "refreshing stub: " - "dns_db_findnode() failed: %s", - dns_result_totext(result)); - goto cleanup; - } + /* + * If the zone is loaded and there are answers check the serial + * to see if we need to do a refresh. Do not worry about this + * check if we are a dialup zone as we use the notify request + * to trigger a refresh check. + */ + if (msg->counts[DNS_SECTION_ANSWER] > 0 && + DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOREFRESH)) { + result = dns_message_findname(msg, DNS_SECTION_ANSWER, + &zone->origin, + dns_rdatatype_soa, + dns_rdatatype_none, NULL, + &rdataset); + if (result == ISC_R_SUCCESS) + result = dns_rdataset_first(rdataset); + if (result == ISC_R_SUCCESS) { + isc_uint32_t serial = 0, oldserial; - result = dns_db_addrdataset(stub->db, node, stub->version, 0, - soardataset, 0, NULL); - dns_db_detachnode(stub->db, &node); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_INFO, - "refreshing stub: " - "dns_db_addrdataset() failed: %s", - dns_result_totext(result)); - goto cleanup; + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &soa, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + serial = soa.serial; + /* + * The following should safely be performed without DB + * lock and succeed in this context. + */ + result = zone_get_from_db(zone, zone->db, NULL, NULL, + &oldserial, NULL, NULL, NULL, + NULL, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (isc_serial_le(serial, oldserial)) { + dns_zone_log(zone, + ISC_LOG_INFO, + "notify from %s: " + "zone is up to date", + fromtext); + UNLOCK_ZONE(zone); + return (ISC_R_SUCCESS); + } } } /* - * XXX Optimisation: Create message when zone is setup and reuse. + * If we got this far and there was a refresh in progress just + * let it complete. Record where we got the notify from so we + * can perform a refresh check when the current one completes */ - result = create_query(zone, dns_rdatatype_ns, &message); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH)) { + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDREFRESH); + zone->notifyfrom = *from; + UNLOCK_ZONE(zone); + dns_zone_log(zone, ISC_LOG_INFO, + "notify from %s: refresh in progress, " + "refresh check queued", + fromtext); + return (ISC_R_SUCCESS); + } + zone->notifyfrom = *from; + UNLOCK_ZONE(zone); + dns_zone_refresh(zone); + return (ISC_R_SUCCESS); +} - INSIST(zone->masterscnt > 0); - INSIST(zone->curmaster < zone->masterscnt); - zone->masteraddr = zone->masters[zone->curmaster]; +void +dns_zone_setnotifyacl(dns_zone_t *zone, dns_acl_t *acl) { - isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); - /* - * First, look for a tsig key in the master statement, then - * try for a server key. - */ - if ((zone->masterkeynames != NULL) && - (zone->masterkeynames[zone->curmaster] != NULL)) { - dns_view_t *view = dns_zone_getview(zone); - dns_name_t *keyname = zone->masterkeynames[zone->curmaster]; - result = dns_view_gettsig(view, keyname, &key); - if (result != ISC_R_SUCCESS) { - char namebuf[DNS_NAME_FORMATSIZE]; - dns_name_format(keyname, namebuf, sizeof(namebuf)); - dns_zone_log(zone, ISC_LOG_ERROR, - "unable to find key: %s", namebuf); - } - } - if (key == NULL) - (void)dns_view_getpeertsig(zone->view, &masterip, &key); + REQUIRE(DNS_ZONE_VALID(zone)); - reqnsid = zone->view->requestnsid; - if (zone->view->peers != NULL) { - dns_peer_t *peer = NULL; - isc_boolean_t edns; - result = dns_peerlist_peerbyaddr(zone->view->peers, - &masterip, &peer); - if (result == ISC_R_SUCCESS) { - result = dns_peer_getsupportedns(peer, &edns); - if (result == ISC_R_SUCCESS && !edns) - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); - result = dns_peer_gettransfersource(peer, - &zone->sourceaddr); - if (result == ISC_R_SUCCESS) - have_xfrsource = ISC_TRUE; - if (zone->view->resolver != NULL) - udpsize = - dns_resolver_getudpsize(zone->view->resolver); - (void)dns_peer_getudpsize(peer, &udpsize); - (void)dns_peer_getrequestnsid(peer, &reqnsid); - } + LOCK_ZONE(zone); + if (zone->notify_acl != NULL) + dns_acl_detach(&zone->notify_acl); + dns_acl_attach(acl, &zone->notify_acl); + UNLOCK_ZONE(zone); +} - } - if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { - result = add_opt(message, udpsize, reqnsid); - if (result != ISC_R_SUCCESS) - zone_debuglog(zone, me, 1, - "unable to add opt record: %s", - dns_result_totext(result)); - } +void +dns_zone_setqueryacl(dns_zone_t *zone, dns_acl_t *acl) { - /* - * Always use TCP so that we shouldn't truncate in additional section. - */ - switch (isc_sockaddr_pf(&zone->masteraddr)) { - case PF_INET: - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) - zone->sourceaddr = zone->altxfrsource4; - else if (!have_xfrsource) - zone->sourceaddr = zone->xfrsource4; - break; - case PF_INET6: - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) - zone->sourceaddr = zone->altxfrsource6; - else if (!have_xfrsource) - zone->sourceaddr = zone->xfrsource6; - break; - default: - result = ISC_R_NOTIMPLEMENTED; - goto cleanup; - } - timeout = 15; - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)) - timeout = 30; - result = dns_request_createvia2(zone->view->requestmgr, message, - &zone->sourceaddr, &zone->masteraddr, - DNS_REQUESTOPT_TCP, key, timeout * 3, - timeout, zone->task, stub_callback, - stub, &zone->request); - if (result != ISC_R_SUCCESS) { - zone_debuglog(zone, me, 1, - "dns_request_createvia() failed: %s", - dns_result_totext(result)); - goto cleanup; - } - dns_message_destroy(&message); - goto unlock; + REQUIRE(DNS_ZONE_VALID(zone)); - cleanup: - cancel_refresh(zone); - if (stub != NULL) { - stub->magic = 0; - if (stub->version != NULL) - dns_db_closeversion(stub->db, &stub->version, - ISC_FALSE); - if (stub->db != NULL) - dns_db_detach(&stub->db); - if (stub->zone != NULL) - zone_idetach(&stub->zone); - isc_mem_put(stub->mctx, stub, sizeof(*stub)); - } - if (message != NULL) - dns_message_destroy(&message); - unlock: - if (key != NULL) - dns_tsigkey_detach(&key); + LOCK_ZONE(zone); + if (zone->query_acl != NULL) + dns_acl_detach(&zone->query_acl); + dns_acl_attach(acl, &zone->query_acl); UNLOCK_ZONE(zone); - return; } -/* - * Handle the control event. Note that although this event causes the zone - * to shut down, it is not a shutdown event in the sense of the task library. - */ -static void -zone_shutdown(isc_task_t *task, isc_event_t *event) { - dns_zone_t *zone = (dns_zone_t *) event->ev_arg; - isc_boolean_t free_needed, linked = ISC_FALSE; +void +dns_zone_setqueryonacl(dns_zone_t *zone, dns_acl_t *acl) { - UNUSED(task); REQUIRE(DNS_ZONE_VALID(zone)); - INSIST(event->ev_type == DNS_EVENT_ZONECONTROL); - INSIST(isc_refcount_current(&zone->erefs) == 0); - zone_debuglog(zone, "zone_shutdown", 3, "shutting down"); - /* - * Stop things being restarted after we cancel them below. - */ LOCK_ZONE(zone); - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_EXITING); + if (zone->queryon_acl != NULL) + dns_acl_detach(&zone->queryon_acl); + dns_acl_attach(acl, &zone->queryon_acl); UNLOCK_ZONE(zone); +} - /* - * If we were waiting for xfrin quota, step out of - * the queue. - * If there's no zone manager, we can't be waiting for the - * xfrin quota - */ - if (zone->zmgr != NULL) { - RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); - if (zone->statelist == &zone->zmgr->waiting_for_xfrin) { - ISC_LIST_UNLINK(zone->zmgr->waiting_for_xfrin, zone, - statelink); - linked = ISC_TRUE; - zone->statelist = NULL; - } - RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); - } +void +dns_zone_setupdateacl(dns_zone_t *zone, dns_acl_t *acl) { - /* - * In task context, no locking required. See zone_xfrdone(). - */ - if (zone->xfr != NULL) - dns_xfrin_shutdown(zone->xfr); + REQUIRE(DNS_ZONE_VALID(zone)); LOCK_ZONE(zone); - if (linked) { - INSIST(zone->irefs > 0); - zone->irefs--; - } - if (zone->request != NULL) { - dns_request_cancel(zone->request); - } + if (zone->update_acl != NULL) + dns_acl_detach(&zone->update_acl); + dns_acl_attach(acl, &zone->update_acl); + UNLOCK_ZONE(zone); +} - if (zone->readio != NULL) - zonemgr_cancelio(zone->readio); +void +dns_zone_setforwardacl(dns_zone_t *zone, dns_acl_t *acl) { - if (zone->lctx != NULL) - dns_loadctx_cancel(zone->lctx); + REQUIRE(DNS_ZONE_VALID(zone)); - if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FLUSH) || - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { - if (zone->writeio != NULL) - zonemgr_cancelio(zone->writeio); + LOCK_ZONE(zone); + if (zone->forward_acl != NULL) + dns_acl_detach(&zone->forward_acl); + dns_acl_attach(acl, &zone->forward_acl); + UNLOCK_ZONE(zone); +} - if (zone->dctx != NULL) - dns_dumpctx_cancel(zone->dctx); - } +void +dns_zone_setxfracl(dns_zone_t *zone, dns_acl_t *acl) { - notify_cancel(zone); + REQUIRE(DNS_ZONE_VALID(zone)); - if (zone->timer != NULL) { - isc_timer_detach(&zone->timer); - INSIST(zone->irefs > 0); - zone->irefs--; - } + LOCK_ZONE(zone); + if (zone->xfr_acl != NULL) + dns_acl_detach(&zone->xfr_acl); + dns_acl_attach(acl, &zone->xfr_acl); + UNLOCK_ZONE(zone); +} - if (zone->view != NULL) - dns_view_weakdetach(&zone->view); +dns_acl_t * +dns_zone_getnotifyacl(dns_zone_t *zone) { - /* - * We have now canceled everything set the flag to allow exit_check() - * to succeed. We must not unlock between setting this flag and - * calling exit_check(). - */ - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SHUTDOWN); - free_needed = exit_check(zone); - UNLOCK_ZONE(zone); - if (free_needed) - zone_free(zone); + REQUIRE(DNS_ZONE_VALID(zone)); + + return (zone->notify_acl); } -static void -zone_timer(isc_task_t *task, isc_event_t *event) { - const char me[] = "zone_timer"; - dns_zone_t *zone = (dns_zone_t *)event->ev_arg; +dns_acl_t * +dns_zone_getqueryacl(dns_zone_t *zone) { - UNUSED(task); REQUIRE(DNS_ZONE_VALID(zone)); - ENTER; + return (zone->query_acl); +} - zone_maintenance(zone); +dns_acl_t * +dns_zone_getqueryonacl(dns_zone_t *zone) { - isc_event_free(&event); + REQUIRE(DNS_ZONE_VALID(zone)); + + return (zone->queryon_acl); } -static void -zone_settimer(dns_zone_t *zone, isc_time_t *now) { - const char me[] = "zone_settimer"; - isc_time_t next; - isc_result_t result; +dns_acl_t * +dns_zone_getupdateacl(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) - return; - isc_time_settoepoch(&next); + return (zone->update_acl); +} - switch (zone->type) { - case dns_zone_master: - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY)) - next = zone->notifytime; - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { - INSIST(!isc_time_isepoch(&zone->dumptime)); - if (isc_time_isepoch(&next) || - isc_time_compare(&zone->dumptime, &next) < 0) - next = zone->dumptime; - } - if (!isc_time_isepoch(&zone->resigntime)) { - if (isc_time_isepoch(&next) || - isc_time_compare(&zone->resigntime, &next) < 0) - next = zone->resigntime; - } - if (!isc_time_isepoch(&zone->keywarntime)) { - if (isc_time_isepoch(&next) || - isc_time_compare(&zone->keywarntime, &next) < 0) - next = zone->keywarntime; - } - if (!isc_time_isepoch(&zone->signingtime)) { - if (isc_time_isepoch(&next) || - isc_time_compare(&zone->signingtime, &next) < 0) - next = zone->signingtime; - } - if (!isc_time_isepoch(&zone->nsec3chaintime)) { - if (isc_time_isepoch(&next) || - isc_time_compare(&zone->nsec3chaintime, &next) < 0) - next = zone->nsec3chaintime; - } - break; +dns_acl_t * +dns_zone_getforwardacl(dns_zone_t *zone) { - case dns_zone_slave: - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY)) - next = zone->notifytime; - /*FALLTHROUGH*/ + REQUIRE(DNS_ZONE_VALID(zone)); - case dns_zone_stub: - if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH) && - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOMASTERS) && - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOREFRESH) && - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADING)) { - INSIST(!isc_time_isepoch(&zone->refreshtime)); - if (isc_time_isepoch(&next) || - isc_time_compare(&zone->refreshtime, &next) < 0) - next = zone->refreshtime; - } - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) { - INSIST(!isc_time_isepoch(&zone->expiretime)); - if (isc_time_isepoch(&next) || - isc_time_compare(&zone->expiretime, &next) < 0) - next = zone->expiretime; - } - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) && - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) { - INSIST(!isc_time_isepoch(&zone->dumptime)); - if (isc_time_isepoch(&next) || - isc_time_compare(&zone->dumptime, &next) < 0) - next = zone->dumptime; - } - break; + return (zone->forward_acl); +} - default: - break; - } +dns_acl_t * +dns_zone_getxfracl(dns_zone_t *zone) { - if (isc_time_isepoch(&next)) { - zone_debuglog(zone, me, 10, "settimer inactive"); - result = isc_timer_reset(zone->timer, isc_timertype_inactive, - NULL, NULL, ISC_TRUE); - if (result != ISC_R_SUCCESS) - dns_zone_log(zone, ISC_LOG_ERROR, - "could not deactivate zone timer: %s", - isc_result_totext(result)); - } else { - if (isc_time_compare(&next, now) <= 0) - next = *now; - result = isc_timer_reset(zone->timer, isc_timertype_once, - &next, NULL, ISC_TRUE); - if (result != ISC_R_SUCCESS) - dns_zone_log(zone, ISC_LOG_ERROR, - "could not reset zone timer: %s", - isc_result_totext(result)); - } + REQUIRE(DNS_ZONE_VALID(zone)); + + return (zone->xfr_acl); } -static void -cancel_refresh(dns_zone_t *zone) { - const char me[] = "cancel_refresh"; - isc_time_t now; +void +dns_zone_clearupdateacl(dns_zone_t *zone) { - /* - * 'zone' locked by caller. - */ + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + if (zone->update_acl != NULL) + dns_acl_detach(&zone->update_acl); + UNLOCK_ZONE(zone); +} + +void +dns_zone_clearforwardacl(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(LOCKED_ZONE(zone)); - ENTER; + LOCK_ZONE(zone); + if (zone->forward_acl != NULL) + dns_acl_detach(&zone->forward_acl); + UNLOCK_ZONE(zone); +} - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); - TIME_NOW(&now); - zone_settimer(zone, &now); +void +dns_zone_clearnotifyacl(dns_zone_t *zone) { + + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + if (zone->notify_acl != NULL) + dns_acl_detach(&zone->notify_acl); + UNLOCK_ZONE(zone); } -static isc_result_t -notify_createmessage(dns_zone_t *zone, unsigned int flags, - dns_message_t **messagep) -{ - dns_db_t *zonedb = NULL; - dns_dbnode_t *node = NULL; - dns_dbversion_t *version = NULL; - dns_message_t *message = NULL; - dns_rdataset_t rdataset; - dns_rdata_t rdata = DNS_RDATA_INIT; +void +dns_zone_clearqueryacl(dns_zone_t *zone) { - dns_name_t *tempname = NULL; - dns_rdata_t *temprdata = NULL; - dns_rdatalist_t *temprdatalist = NULL; - dns_rdataset_t *temprdataset = NULL; + REQUIRE(DNS_ZONE_VALID(zone)); - isc_result_t result; - isc_region_t r; - isc_buffer_t *b = NULL; + LOCK_ZONE(zone); + if (zone->query_acl != NULL) + dns_acl_detach(&zone->query_acl); + UNLOCK_ZONE(zone); +} + +void +dns_zone_clearqueryonacl(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(messagep != NULL && *messagep == NULL); - result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTRENDER, - &message); - if (result != ISC_R_SUCCESS) - return (result); + LOCK_ZONE(zone); + if (zone->queryon_acl != NULL) + dns_acl_detach(&zone->queryon_acl); + UNLOCK_ZONE(zone); +} - message->opcode = dns_opcode_notify; - message->flags |= DNS_MESSAGEFLAG_AA; - message->rdclass = zone->rdclass; +void +dns_zone_clearxfracl(dns_zone_t *zone) { - result = dns_message_gettempname(message, &tempname); - if (result != ISC_R_SUCCESS) - goto cleanup; + REQUIRE(DNS_ZONE_VALID(zone)); - result = dns_message_gettemprdataset(message, &temprdataset); - if (result != ISC_R_SUCCESS) - goto cleanup; + LOCK_ZONE(zone); + if (zone->xfr_acl != NULL) + dns_acl_detach(&zone->xfr_acl); + UNLOCK_ZONE(zone); +} - /* - * Make question. - */ - dns_name_init(tempname, NULL); - dns_name_clone(&zone->origin, tempname); - dns_rdataset_init(temprdataset); - dns_rdataset_makequestion(temprdataset, zone->rdclass, - dns_rdatatype_soa); - ISC_LIST_APPEND(tempname->list, temprdataset, link); - dns_message_addname(message, tempname, DNS_SECTION_QUESTION); - tempname = NULL; - temprdataset = NULL; +isc_boolean_t +dns_zone_getupdatedisabled(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (zone->update_disabled); - if ((flags & DNS_NOTIFY_NOSOA) != 0) - goto done; +} - result = dns_message_gettempname(message, &tempname); - if (result != ISC_R_SUCCESS) - goto soa_cleanup; - result = dns_message_gettemprdata(message, &temprdata); - if (result != ISC_R_SUCCESS) - goto soa_cleanup; - result = dns_message_gettemprdataset(message, &temprdataset); - if (result != ISC_R_SUCCESS) - goto soa_cleanup; - result = dns_message_gettemprdatalist(message, &temprdatalist); - if (result != ISC_R_SUCCESS) - goto soa_cleanup; +void +dns_zone_setupdatedisabled(dns_zone_t *zone, isc_boolean_t state) { + REQUIRE(DNS_ZONE_VALID(zone)); + zone->update_disabled = state; +} + +isc_boolean_t +dns_zone_getzeronosoattl(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (zone->zero_no_soa_ttl); + +} - ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); - INSIST(zone->db != NULL); /* XXXJT: is this assumption correct? */ - dns_db_attach(zone->db, &zonedb); - ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); +void +dns_zone_setzeronosoattl(dns_zone_t *zone, isc_boolean_t state) { + REQUIRE(DNS_ZONE_VALID(zone)); + zone->zero_no_soa_ttl = state; +} - dns_name_init(tempname, NULL); - dns_name_clone(&zone->origin, tempname); - dns_db_currentversion(zonedb, &version); - result = dns_db_findnode(zonedb, tempname, ISC_FALSE, &node); - if (result != ISC_R_SUCCESS) - goto soa_cleanup; +void +dns_zone_setchecknames(dns_zone_t *zone, dns_severity_t severity) { - dns_rdataset_init(&rdataset); - result = dns_db_findrdataset(zonedb, node, version, - dns_rdatatype_soa, - dns_rdatatype_none, 0, &rdataset, - NULL); - if (result != ISC_R_SUCCESS) - goto soa_cleanup; - result = dns_rdataset_first(&rdataset); - if (result != ISC_R_SUCCESS) - goto soa_cleanup; - dns_rdataset_current(&rdataset, &rdata); - dns_rdata_toregion(&rdata, &r); - result = isc_buffer_allocate(zone->mctx, &b, r.length); - if (result != ISC_R_SUCCESS) - goto soa_cleanup; - isc_buffer_putmem(b, r.base, r.length); - isc_buffer_usedregion(b, &r); - dns_rdata_init(temprdata); - dns_rdata_fromregion(temprdata, rdata.rdclass, rdata.type, &r); - dns_message_takebuffer(message, &b); - result = dns_rdataset_next(&rdataset); - dns_rdataset_disassociate(&rdataset); - if (result != ISC_R_NOMORE) - goto soa_cleanup; - temprdatalist->rdclass = rdata.rdclass; - temprdatalist->type = rdata.type; - temprdatalist->covers = 0; - temprdatalist->ttl = rdataset.ttl; - ISC_LIST_INIT(temprdatalist->rdata); - ISC_LIST_APPEND(temprdatalist->rdata, temprdata, link); + REQUIRE(DNS_ZONE_VALID(zone)); - dns_rdataset_init(temprdataset); - result = dns_rdatalist_tordataset(temprdatalist, temprdataset); - if (result != ISC_R_SUCCESS) - goto soa_cleanup; + zone->check_names = severity; +} - ISC_LIST_APPEND(tempname->list, temprdataset, link); - dns_message_addname(message, tempname, DNS_SECTION_ANSWER); - temprdatalist = NULL; - temprdataset = NULL; - temprdata = NULL; - tempname = NULL; +dns_severity_t +dns_zone_getchecknames(dns_zone_t *zone) { - soa_cleanup: - if (node != NULL) - dns_db_detachnode(zonedb, &node); - if (version != NULL) - dns_db_closeversion(zonedb, &version, ISC_FALSE); - if (zonedb != NULL) - dns_db_detach(&zonedb); - if (tempname != NULL) - dns_message_puttempname(message, &tempname); - if (temprdata != NULL) - dns_message_puttemprdata(message, &temprdata); - if (temprdataset != NULL) - dns_message_puttemprdataset(message, &temprdataset); - if (temprdatalist != NULL) - dns_message_puttemprdatalist(message, &temprdatalist); + REQUIRE(DNS_ZONE_VALID(zone)); - done: - *messagep = message; - return (ISC_R_SUCCESS); + return (zone->check_names); +} - cleanup: - if (tempname != NULL) - dns_message_puttempname(message, &tempname); - if (temprdataset != NULL) - dns_message_puttemprdataset(message, &temprdataset); - dns_message_destroy(&message); - return (result); +void +dns_zone_setjournalsize(dns_zone_t *zone, isc_int32_t size) { + + REQUIRE(DNS_ZONE_VALID(zone)); + + zone->journalsize = size; } -isc_result_t -dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, - dns_message_t *msg) -{ - unsigned int i; - dns_rdata_soa_t soa; - dns_rdataset_t *rdataset = NULL; - dns_rdata_t rdata = DNS_RDATA_INIT; - isc_result_t result; - char fromtext[ISC_SOCKADDR_FORMATSIZE]; - int match = 0; - isc_netaddr_t netaddr; +isc_int32_t +dns_zone_getjournalsize(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); - /* - * If type != T_SOA return DNS_R_REFUSED. We don't yet support - * ROLLOVER. - * - * SOA: RFC1996 - * Check that 'from' is a valid notify source, (zone->masters). - * Return DNS_R_REFUSED if not. - * - * If the notify message contains a serial number check it - * against the zones serial and return if <= current serial - * - * If a refresh check is progress, if so just record the - * fact we received a NOTIFY and from where and return. - * We will perform a new refresh check when the current one - * completes. Return ISC_R_SUCCESS. - * - * Otherwise initiate a refresh check using 'from' as the - * first address to check. Return ISC_R_SUCCESS. - */ + return (zone->journalsize); +} - isc_sockaddr_format(from, fromtext, sizeof(fromtext)); +static void +zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length) { + isc_result_t result = ISC_R_FAILURE; + isc_buffer_t buffer; - /* - * We only handle NOTIFY (SOA) at the present. - */ - LOCK_ZONE(zone); - if (isc_sockaddr_pf(from) == PF_INET) - inc_stats(zone, dns_zonestatscounter_notifyinv4); - else - inc_stats(zone, dns_zonestatscounter_notifyinv6); - if (msg->counts[DNS_SECTION_QUESTION] == 0 || - dns_message_findname(msg, DNS_SECTION_QUESTION, &zone->origin, - dns_rdatatype_soa, dns_rdatatype_none, - NULL, NULL) != ISC_R_SUCCESS) { - UNLOCK_ZONE(zone); - if (msg->counts[DNS_SECTION_QUESTION] == 0) { - dns_zone_log(zone, ISC_LOG_NOTICE, - "NOTIFY with no " - "question section from: %s", fromtext); - return (DNS_R_FORMERR); - } - dns_zone_log(zone, ISC_LOG_NOTICE, - "NOTIFY zone does not match"); - return (DNS_R_NOTIMP); - } + REQUIRE(buf != NULL); + REQUIRE(length > 1U); /* - * If we are a master zone just succeed. + * Leave space for terminating '\0'. */ - if (zone->type == dns_zone_master) { - UNLOCK_ZONE(zone); - return (ISC_R_SUCCESS); - } + isc_buffer_init(&buffer, buf, length - 1); + if (dns_name_dynamic(&zone->origin)) + result = dns_name_totext(&zone->origin, ISC_TRUE, &buffer); + if (result != ISC_R_SUCCESS && + isc_buffer_availablelength(&buffer) >= (sizeof("") - 1)) + isc_buffer_putstr(&buffer, ""); - isc_netaddr_fromsockaddr(&netaddr, from); - for (i = 0; i < zone->masterscnt; i++) { - if (isc_sockaddr_eqaddr(from, &zone->masters[i])) - break; - if (zone->view->aclenv.match_mapped && - IN6_IS_ADDR_V4MAPPED(&from->type.sin6.sin6_addr) && - isc_sockaddr_pf(&zone->masters[i]) == AF_INET) { - isc_netaddr_t na1, na2; - isc_netaddr_fromv4mapped(&na1, &netaddr); - isc_netaddr_fromsockaddr(&na2, &zone->masters[i]); - if (isc_netaddr_equal(&na1, &na2)) - break; - } + if (isc_buffer_availablelength(&buffer) > 0) + isc_buffer_putstr(&buffer, "/"); + (void)dns_rdataclass_totext(zone->rdclass, &buffer); + + if (zone->view != NULL && strcmp(zone->view->name, "_bind") != 0 && + strcmp(zone->view->name, "_default") != 0 && + strlen(zone->view->name) < isc_buffer_availablelength(&buffer)) { + isc_buffer_putstr(&buffer, "/"); + isc_buffer_putstr(&buffer, zone->view->name); } + buf[isc_buffer_usedlength(&buffer)] = '\0'; +} + +static void +zone_name_tostr(dns_zone_t *zone, char *buf, size_t length) { + isc_result_t result = ISC_R_FAILURE; + isc_buffer_t buffer; + + REQUIRE(buf != NULL); + REQUIRE(length > 1U); + /* - * Accept notify requests from non masters if they are on - * 'zone->notify_acl'. + * Leave space for terminating '\0'. */ - if (i >= zone->masterscnt && zone->notify_acl != NULL && - dns_acl_match(&netaddr, NULL, zone->notify_acl, - &zone->view->aclenv, - &match, NULL) == ISC_R_SUCCESS && - match > 0) - { - /* Accept notify. */ - } else if (i >= zone->masterscnt) { - UNLOCK_ZONE(zone); - dns_zone_log(zone, ISC_LOG_INFO, - "refused notify from non-master: %s", fromtext); - inc_stats(zone, dns_zonestatscounter_notifyrej); - return (DNS_R_REFUSED); - } + isc_buffer_init(&buffer, buf, length - 1); + if (dns_name_dynamic(&zone->origin)) + result = dns_name_totext(&zone->origin, ISC_TRUE, &buffer); + if (result != ISC_R_SUCCESS && + isc_buffer_availablelength(&buffer) >= (sizeof("") - 1)) + isc_buffer_putstr(&buffer, ""); + + buf[isc_buffer_usedlength(&buffer)] = '\0'; +} + +static void +zone_rdclass_tostr(dns_zone_t *zone, char *buf, size_t length) { + isc_buffer_t buffer; + + REQUIRE(buf != NULL); + REQUIRE(length > 1U); /* - * If the zone is loaded and there are answers check the serial - * to see if we need to do a refresh. Do not worry about this - * check if we are a dialup zone as we use the notify request - * to trigger a refresh check. - */ - if (msg->counts[DNS_SECTION_ANSWER] > 0 && - DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) && - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOREFRESH)) { - result = dns_message_findname(msg, DNS_SECTION_ANSWER, - &zone->origin, - dns_rdatatype_soa, - dns_rdatatype_none, NULL, - &rdataset); - if (result == ISC_R_SUCCESS) - result = dns_rdataset_first(rdataset); - if (result == ISC_R_SUCCESS) { - isc_uint32_t serial = 0, oldserial; + * Leave space for terminating '\0'. + */ + isc_buffer_init(&buffer, buf, length - 1); + (void)dns_rdataclass_totext(zone->rdclass, &buffer); + + buf[isc_buffer_usedlength(&buffer)] = '\0'; +} + +static void +zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length) { + isc_buffer_t buffer; + + REQUIRE(buf != NULL); + REQUIRE(length > 1U); - dns_rdataset_current(rdataset, &rdata); - result = dns_rdata_tostruct(&rdata, &soa, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - serial = soa.serial; - /* - * The following should safely be performed without DB - * lock and succeed in this context. - */ - result = zone_get_from_db(zone, zone->db, NULL, NULL, - &oldserial, NULL, NULL, NULL, - NULL, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - if (isc_serial_le(serial, oldserial)) { - dns_zone_log(zone, ISC_LOG_INFO, - "notify from %s: " - "zone is up to date", - fromtext); - UNLOCK_ZONE(zone); - return (ISC_R_SUCCESS); - } - } - } /* - * If we got this far and there was a refresh in progress just - * let it complete. Record where we got the notify from so we - * can perform a refresh check when the current one completes + * Leave space for terminating '\0'. */ - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH)) { - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDREFRESH); - zone->notifyfrom = *from; - UNLOCK_ZONE(zone); - dns_zone_log(zone, ISC_LOG_INFO, - "notify from %s: refresh in progress, " - "refresh check queued", - fromtext); - return (ISC_R_SUCCESS); + isc_buffer_init(&buffer, buf, length - 1); + + if (zone->view == NULL) { + isc_buffer_putstr(&buffer, "_none"); + } else if (strlen(zone->view->name) + < isc_buffer_availablelength(&buffer)) { + isc_buffer_putstr(&buffer, zone->view->name); + } else { + isc_buffer_putstr(&buffer, "_toolong"); } - zone->notifyfrom = *from; - UNLOCK_ZONE(zone); - dns_zone_refresh(zone); - return (ISC_R_SUCCESS); + + buf[isc_buffer_usedlength(&buffer)] = '\0'; } void -dns_zone_setnotifyacl(dns_zone_t *zone, dns_acl_t *acl) { - +dns_zone_name(dns_zone_t *zone, char *buf, size_t length) { REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(buf != NULL); + zone_namerd_tostr(zone, buf, length); +} - LOCK_ZONE(zone); - if (zone->notify_acl != NULL) - dns_acl_detach(&zone->notify_acl); - dns_acl_attach(acl, &zone->notify_acl); - UNLOCK_ZONE(zone); +static void +notify_log(dns_zone_t *zone, int level, const char *fmt, ...) { + va_list ap; + char message[4096]; + + if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) + return; + + va_start(ap, fmt); + vsnprintf(message, sizeof(message), fmt, ap); + va_end(ap); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_NOTIFY, DNS_LOGMODULE_ZONE, + level, "zone %s: %s", zone->strnamerd, message); } void -dns_zone_setqueryacl(dns_zone_t *zone, dns_acl_t *acl) { +dns_zone_logc(dns_zone_t *zone, isc_logcategory_t *category, + int level, const char *fmt, ...) { + va_list ap; + char message[4096]; - REQUIRE(DNS_ZONE_VALID(zone)); + if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) + return; - LOCK_ZONE(zone); - if (zone->query_acl != NULL) - dns_acl_detach(&zone->query_acl); - dns_acl_attach(acl, &zone->query_acl); - UNLOCK_ZONE(zone); + va_start(ap, fmt); + vsnprintf(message, sizeof(message), fmt, ap); + va_end(ap); + isc_log_write(dns_lctx, category, DNS_LOGMODULE_ZONE, + level, "%s %s: %s", (zone->type == dns_zone_key) ? + "managed-keys-zone" : "zone", zone->strnamerd, message); } void -dns_zone_setqueryonacl(dns_zone_t *zone, dns_acl_t *acl) { +dns_zone_log(dns_zone_t *zone, int level, const char *fmt, ...) { + va_list ap; + char message[4096]; - REQUIRE(DNS_ZONE_VALID(zone)); + if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) + return; - LOCK_ZONE(zone); - if (zone->queryon_acl != NULL) - dns_acl_detach(&zone->queryon_acl); - dns_acl_attach(acl, &zone->queryon_acl); - UNLOCK_ZONE(zone); + va_start(ap, fmt); + vsnprintf(message, sizeof(message), fmt, ap); + va_end(ap); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, + level, "%s %s: %s", (zone->type == dns_zone_key) ? + "managed-keys-zone" : "zone", zone->strnamerd, message); } -void -dns_zone_setupdateacl(dns_zone_t *zone, dns_acl_t *acl) { +static void +zone_debuglog(dns_zone_t *zone, const char *me, int debuglevel, + const char *fmt, ...) +{ + va_list ap; + char message[4096]; + int level = ISC_LOG_DEBUG(debuglevel); - REQUIRE(DNS_ZONE_VALID(zone)); + if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) + return; - LOCK_ZONE(zone); - if (zone->update_acl != NULL) - dns_acl_detach(&zone->update_acl); - dns_acl_attach(acl, &zone->update_acl); - UNLOCK_ZONE(zone); + va_start(ap, fmt); + vsnprintf(message, sizeof(message), fmt, ap); + va_end(ap); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, + level, "%s: %s %s: %s", me, zone->type != dns_zone_key ? + "zone" : "managed-keys-zone", zone->strnamerd, message); } -void -dns_zone_setforwardacl(dns_zone_t *zone, dns_acl_t *acl) { +static int +message_count(dns_message_t *msg, dns_section_t section, dns_rdatatype_t type) +{ + isc_result_t result; + dns_name_t *name; + dns_rdataset_t *curr; + int count = 0; - REQUIRE(DNS_ZONE_VALID(zone)); + result = dns_message_firstname(msg, section); + while (result == ISC_R_SUCCESS) { + name = NULL; + dns_message_currentname(msg, section, &name); - LOCK_ZONE(zone); - if (zone->forward_acl != NULL) - dns_acl_detach(&zone->forward_acl); - dns_acl_attach(acl, &zone->forward_acl); - UNLOCK_ZONE(zone); + for (curr = ISC_LIST_TAIL(name->list); curr != NULL; + curr = ISC_LIST_PREV(curr, link)) { + if (curr->type == type) + count++; + } + result = dns_message_nextname(msg, section); + } + + return (count); } void -dns_zone_setxfracl(dns_zone_t *zone, dns_acl_t *acl) { - +dns_zone_setmaxxfrin(dns_zone_t *zone, isc_uint32_t maxxfrin) { REQUIRE(DNS_ZONE_VALID(zone)); - LOCK_ZONE(zone); - if (zone->xfr_acl != NULL) - dns_acl_detach(&zone->xfr_acl); - dns_acl_attach(acl, &zone->xfr_acl); - UNLOCK_ZONE(zone); + zone->maxxfrin = maxxfrin; } -dns_acl_t * -dns_zone_getnotifyacl(dns_zone_t *zone) { - +isc_uint32_t +dns_zone_getmaxxfrin(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); - return (zone->notify_acl); + return (zone->maxxfrin); } -dns_acl_t * -dns_zone_getqueryacl(dns_zone_t *zone) { +void +dns_zone_setmaxxfrout(dns_zone_t *zone, isc_uint32_t maxxfrout) { + REQUIRE(DNS_ZONE_VALID(zone)); + zone->maxxfrout = maxxfrout; +} +isc_uint32_t +dns_zone_getmaxxfrout(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); - return (zone->query_acl); + return (zone->maxxfrout); } -dns_acl_t * -dns_zone_getqueryonacl(dns_zone_t *zone) { - +dns_zonetype_t +dns_zone_gettype(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); - return (zone->queryon_acl); + return (zone->type); } -dns_acl_t * -dns_zone_getupdateacl(dns_zone_t *zone) { +dns_name_t * +dns_zone_getorigin(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (&zone->origin); +} + +void +dns_zone_settask(dns_zone_t *zone, isc_task_t *task) { REQUIRE(DNS_ZONE_VALID(zone)); - return (zone->update_acl); + LOCK_ZONE(zone); + if (zone->task != NULL) + isc_task_detach(&zone->task); + isc_task_attach(task, &zone->task); + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + if (zone->db != NULL) + dns_db_settask(zone->db, zone->task); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + UNLOCK_ZONE(zone); } -dns_acl_t * -dns_zone_getforwardacl(dns_zone_t *zone) { +void +dns_zone_gettask(dns_zone_t *zone, isc_task_t **target) { + REQUIRE(DNS_ZONE_VALID(zone)); + isc_task_attach(zone->task, target); +} +void +dns_zone_setidlein(dns_zone_t *zone, isc_uint32_t idlein) { REQUIRE(DNS_ZONE_VALID(zone)); - return (zone->forward_acl); + if (idlein == 0) + idlein = DNS_DEFAULT_IDLEIN; + zone->idlein = idlein; } -dns_acl_t * -dns_zone_getxfracl(dns_zone_t *zone) { - +isc_uint32_t +dns_zone_getidlein(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); - return (zone->xfr_acl); + return (zone->idlein); } void -dns_zone_clearupdateacl(dns_zone_t *zone) { +dns_zone_setidleout(dns_zone_t *zone, isc_uint32_t idleout) { + REQUIRE(DNS_ZONE_VALID(zone)); + + zone->idleout = idleout; +} + +isc_uint32_t +dns_zone_getidleout(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + + return (zone->idleout); +} - REQUIRE(DNS_ZONE_VALID(zone)); +static void +notify_done(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *revent = (dns_requestevent_t *)event; + dns_notify_t *notify; + isc_result_t result; + dns_message_t *message = NULL; + isc_buffer_t buf; + char rcode[128]; + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; - LOCK_ZONE(zone); - if (zone->update_acl != NULL) - dns_acl_detach(&zone->update_acl); - UNLOCK_ZONE(zone); -} + UNUSED(task); -void -dns_zone_clearforwardacl(dns_zone_t *zone) { + notify = event->ev_arg; + REQUIRE(DNS_NOTIFY_VALID(notify)); + INSIST(task == notify->zone->task); - REQUIRE(DNS_ZONE_VALID(zone)); + isc_buffer_init(&buf, rcode, sizeof(rcode)); + isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf)); - LOCK_ZONE(zone); - if (zone->forward_acl != NULL) - dns_acl_detach(&zone->forward_acl); - UNLOCK_ZONE(zone); + result = revent->result; + if (result == ISC_R_SUCCESS) + result = dns_message_create(notify->zone->mctx, + DNS_MESSAGE_INTENTPARSE, &message); + if (result == ISC_R_SUCCESS) + result = dns_request_getresponse(revent->request, message, + DNS_MESSAGEPARSE_PRESERVEORDER); + if (result == ISC_R_SUCCESS) + result = dns_rcode_totext(message->rcode, &buf); + if (result == ISC_R_SUCCESS) + notify_log(notify->zone, ISC_LOG_DEBUG(3), + "notify response from %s: %.*s", + addrbuf, (int)buf.used, rcode); + else + notify_log(notify->zone, ISC_LOG_DEBUG(2), + "notify to %s failed: %s", addrbuf, + dns_result_totext(result)); + + /* + * Old bind's return formerr if they see a soa record. Retry w/o + * the soa if we see a formerr and had sent a SOA. + */ + isc_event_free(&event); + if (message != NULL && message->rcode == dns_rcode_formerr && + (notify->flags & DNS_NOTIFY_NOSOA) == 0) { + notify->flags |= DNS_NOTIFY_NOSOA; + dns_request_destroy(¬ify->request); + result = notify_send_queue(notify); + if (result != ISC_R_SUCCESS) + notify_destroy(notify, ISC_FALSE); + } else { + if (result == ISC_R_TIMEDOUT) + notify_log(notify->zone, ISC_LOG_DEBUG(1), + "notify to %s: retries exceeded", addrbuf); + notify_destroy(notify, ISC_FALSE); + } + if (message != NULL) + dns_message_destroy(&message); } -void -dns_zone_clearnotifyacl(dns_zone_t *zone) { +isc_result_t +dns_zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { + isc_result_t result; REQUIRE(DNS_ZONE_VALID(zone)); - LOCK_ZONE(zone); - if (zone->notify_acl != NULL) - dns_acl_detach(&zone->notify_acl); + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); + result = zone_replacedb(zone, db, dump); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); UNLOCK_ZONE(zone); + return (result); } -void -dns_zone_clearqueryacl(dns_zone_t *zone) { +static isc_result_t +zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { + dns_dbversion_t *ver; + isc_result_t result; + unsigned int soacount = 0; + unsigned int nscount = 0; + /* + * 'zone' and 'zonedb' locked by caller. + */ REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(LOCKED_ZONE(zone)); - LOCK_ZONE(zone); - if (zone->query_acl != NULL) - dns_acl_detach(&zone->query_acl); - UNLOCK_ZONE(zone); -} + result = zone_get_from_db(zone, db, &nscount, &soacount, + NULL, NULL, NULL, NULL, NULL, NULL); + if (result == ISC_R_SUCCESS) { + if (soacount != 1) { + dns_zone_log(zone, ISC_LOG_ERROR, + "has %d SOA records", soacount); + result = DNS_R_BADZONE; + } + if (nscount == 0 && zone->type != dns_zone_key) { + dns_zone_log(zone, ISC_LOG_ERROR, "has no NS records"); + result = DNS_R_BADZONE; + } + if (result != ISC_R_SUCCESS) + return (result); + } else { + dns_zone_log(zone, ISC_LOG_ERROR, + "retrieving SOA and NS records failed: %s", + dns_result_totext(result)); + return (result); + } -void -dns_zone_clearqueryonacl(dns_zone_t *zone) { + result = check_nsec3param(zone, db); + if (result != ISC_R_SUCCESS) + return (result); - REQUIRE(DNS_ZONE_VALID(zone)); + ver = NULL; + dns_db_currentversion(db, &ver); - LOCK_ZONE(zone); - if (zone->queryon_acl != NULL) - dns_acl_detach(&zone->queryon_acl); - UNLOCK_ZONE(zone); -} + /* + * The initial version of a slave zone is always dumped; + * subsequent versions may be journaled instead if this + * is enabled in the configuration. + */ + if (zone->db != NULL && zone->journal != NULL && + DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) { + isc_uint32_t serial, oldserial; -void -dns_zone_clearxfracl(dns_zone_t *zone) { + dns_zone_log(zone, ISC_LOG_DEBUG(3), "generating diffs"); - REQUIRE(DNS_ZONE_VALID(zone)); + result = dns_db_getsoaserial(db, ver, &serial); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "ixfr-from-differences: unable to get " + "new serial"); + goto fail; + } - LOCK_ZONE(zone); - if (zone->xfr_acl != NULL) - dns_acl_detach(&zone->xfr_acl); - UNLOCK_ZONE(zone); -} + /* + * This is checked in zone_postload() for master zones. + */ + result = zone_get_from_db(zone, zone->db, NULL, NULL, + &oldserial, NULL, NULL, NULL, NULL, + NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (zone->type == dns_zone_slave && + !isc_serial_gt(serial, oldserial)) { + isc_uint32_t serialmin, serialmax; + serialmin = (oldserial + 1) & 0xffffffffU; + serialmax = (oldserial + 0x7fffffffU) & 0xffffffffU; + dns_zone_log(zone, ISC_LOG_ERROR, + "ixfr-from-differences: failed: " + "new serial (%u) out of range [%u - %u]", + serial, serialmin, serialmax); + result = ISC_R_RANGE; + goto fail; + } -isc_boolean_t -dns_zone_getupdatedisabled(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); - return (zone->update_disabled); + result = dns_db_diff(zone->mctx, db, ver, zone->db, NULL, + zone->journal); + if (result != ISC_R_SUCCESS) + goto fail; + if (dump) + zone_needdump(zone, DNS_DUMP_DELAY); + else if (zone->journalsize != -1) { + result = dns_journal_compact(zone->mctx, zone->journal, + serial, zone->journalsize); + switch (result) { + case ISC_R_SUCCESS: + case ISC_R_NOSPACE: + case ISC_R_NOTFOUND: + dns_zone_log(zone, ISC_LOG_DEBUG(3), + "dns_journal_compact: %s", + dns_result_totext(result)); + break; + default: + dns_zone_log(zone, ISC_LOG_ERROR, + "dns_journal_compact failed: %s", + dns_result_totext(result)); + break; + } + } + } else { + if (dump && zone->masterfile != NULL) { + /* + * If DNS_ZONEFLG_FORCEXFER was set we don't want + * to keep the old masterfile. + */ + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER) && + remove(zone->masterfile) < 0 && errno != ENOENT) { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_ZONE, + ISC_LOG_WARNING, + "unable to remove masterfile " + "'%s': '%s'", + zone->masterfile, strbuf); + } + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) == 0) + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NODELAY); + else + zone_needdump(zone, 0); + } + if (dump && zone->journal != NULL) { + /* + * The in-memory database just changed, and + * because 'dump' is set, it didn't change by + * being loaded from disk. Also, we have not + * journaled diffs for this change. + * Therefore, the on-disk journal is missing + * the deltas for this change. Since it can + * no longer be used to bring the zone + * up-to-date, it is useless and should be + * removed. + */ + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), + "removing journal file"); + if (remove(zone->journal) < 0 && errno != ENOENT) { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(dns_lctx, + DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_ZONE, + ISC_LOG_WARNING, + "unable to remove journal " + "'%s': '%s'", + zone->journal, strbuf); + } + } + } -} + dns_db_closeversion(db, &ver, ISC_FALSE); -void -dns_zone_setupdatedisabled(dns_zone_t *zone, isc_boolean_t state) { - REQUIRE(DNS_ZONE_VALID(zone)); - zone->update_disabled = state; -} + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), + "replacing zone database"); -isc_boolean_t -dns_zone_getzeronosoattl(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); - return (zone->zero_no_soa_ttl); + if (zone->db != NULL) + zone_detachdb(zone); + zone_attachdb(zone, db); + dns_db_settask(zone->db, zone->task); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY); + return (ISC_R_SUCCESS); + fail: + dns_db_closeversion(db, &ver, ISC_FALSE); + return (result); } -void -dns_zone_setzeronosoattl(dns_zone_t *zone, isc_boolean_t state) { - REQUIRE(DNS_ZONE_VALID(zone)); - zone->zero_no_soa_ttl = state; -} +/* The caller must hold the dblock as a writer. */ +static inline void +zone_attachdb(dns_zone_t *zone, dns_db_t *db) { + REQUIRE(zone->db == NULL && db != NULL); -void -dns_zone_setchecknames(dns_zone_t *zone, dns_severity_t severity) { + dns_db_attach(db, &zone->db); + if (zone->acache != NULL) { + isc_result_t result; + result = dns_acache_setdb(zone->acache, db); + if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "dns_acache_setdb() failed: %s", + isc_result_totext(result)); + } + } +} - REQUIRE(DNS_ZONE_VALID(zone)); +/* The caller must hold the dblock as a writer. */ +static inline void +zone_detachdb(dns_zone_t *zone) { + REQUIRE(zone->db != NULL); - zone->check_names = severity; + if (zone->acache != NULL) + (void)dns_acache_putdb(zone->acache, zone->db); + dns_db_detach(&zone->db); } -dns_severity_t -dns_zone_getchecknames(dns_zone_t *zone) { +static void +zone_xfrdone(dns_zone_t *zone, isc_result_t result) { + isc_time_t now; + isc_boolean_t again = ISC_FALSE; + unsigned int soacount; + unsigned int nscount; + isc_uint32_t serial, refresh, retry, expire, minimum; + isc_result_t xfrresult = result; + isc_boolean_t free_needed; REQUIRE(DNS_ZONE_VALID(zone)); - return (zone->check_names); -} - -void -dns_zone_setjournalsize(dns_zone_t *zone, isc_int32_t size) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "zone transfer finished: %s", dns_result_totext(result)); - REQUIRE(DNS_ZONE_VALID(zone)); + LOCK_ZONE(zone); + INSIST((zone->flags & DNS_ZONEFLG_REFRESH) != 0); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR); - zone->journalsize = size; -} + TIME_NOW(&now); + switch (result) { + case ISC_R_SUCCESS: + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); + /*FALLTHROUGH*/ + case DNS_R_UPTODATE: + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_FORCEXFER); + /* + * Has the zone expired underneath us? + */ + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + if (zone->db == NULL) { + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + goto same_master; + } -isc_int32_t -dns_zone_getjournalsize(dns_zone_t *zone) { + /* + * Update the zone structure's data from the actual + * SOA received. + */ + nscount = 0; + soacount = 0; + INSIST(zone->db != NULL); + result = zone_get_from_db(zone, zone->db, &nscount, + &soacount, &serial, &refresh, + &retry, &expire, &minimum, NULL); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + if (result == ISC_R_SUCCESS) { + if (soacount != 1) + dns_zone_log(zone, ISC_LOG_ERROR, + "transferred zone " + "has %d SOA record%s", soacount, + (soacount != 0) ? "s" : ""); + if (nscount == 0) { + dns_zone_log(zone, ISC_LOG_ERROR, + "transferred zone " + "has no NS records"); + if (DNS_ZONE_FLAG(zone, + DNS_ZONEFLG_HAVETIMERS)) { + zone->refresh = DNS_ZONE_DEFAULTREFRESH; + zone->retry = DNS_ZONE_DEFAULTRETRY; + } + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HAVETIMERS); + zone_unload(zone); + goto next_master; + } + zone->refresh = RANGE(refresh, zone->minrefresh, + zone->maxrefresh); + zone->retry = RANGE(retry, zone->minretry, + zone->maxretry); + zone->expire = RANGE(expire, + zone->refresh + zone->retry, + DNS_MAX_EXPIRE); + zone->minimum = minimum; + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS); + } - REQUIRE(DNS_ZONE_VALID(zone)); + /* + * Set our next update/expire times. + */ + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDREFRESH)) { + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDREFRESH); + zone->refreshtime = now; + DNS_ZONE_TIME_ADD(&now, zone->expire, + &zone->expiretime); + } else { + DNS_ZONE_JITTER_ADD(&now, zone->refresh, + &zone->refreshtime); + DNS_ZONE_TIME_ADD(&now, zone->expire, + &zone->expiretime); + } + if (result == ISC_R_SUCCESS && xfrresult == ISC_R_SUCCESS) { + char buf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''")]; + if (zone->tsigkey != NULL) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(&zone->tsigkey->name, namebuf, + sizeof(namebuf)); + snprintf(buf, sizeof(buf), ": TSIG '%s'", + namebuf); + } else + buf[0] = '\0'; + dns_zone_log(zone, ISC_LOG_INFO, + "transferred serial %u%s", + serial, buf); + } - return (zone->journalsize); -} + /* + * This is not necessary if we just performed a AXFR + * however it is necessary for an IXFR / UPTODATE and + * won't hurt with an AXFR. + */ + if (zone->masterfile != NULL || zone->journal != NULL) { + result = ISC_R_FAILURE; + if (zone->journal != NULL) + result = isc_file_settime(zone->journal, &now); + if (result != ISC_R_SUCCESS && + zone->masterfile != NULL) + result = isc_file_settime(zone->masterfile, + &now); + /* Someone removed the file from underneath us! */ + if (result == ISC_R_FILENOTFOUND && + zone->masterfile != NULL) { + unsigned int delay = DNS_DUMP_DELAY; + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NODELAY)) + delay = 0; + zone_needdump(zone, delay); + } else if (result != ISC_R_SUCCESS) + dns_zone_log(zone, ISC_LOG_ERROR, + "transfer: could not set file " + "modification time of '%s': %s", + zone->masterfile, + dns_result_totext(result)); + } + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NODELAY); + inc_stats(zone, dns_zonestatscounter_xfrsuccess); + break; -static void -zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length) { - isc_result_t result = ISC_R_FAILURE; - isc_buffer_t buffer; + case DNS_R_BADIXFR: + /* Force retry with AXFR. */ + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLAG_NOIXFR); + goto same_master; - REQUIRE(buf != NULL); - REQUIRE(length > 1U); + default: + next_master: + /* + * Skip to next failed / untried master. + */ + do { + zone->curmaster++; + } while (zone->curmaster < zone->masterscnt && + zone->mastersok[zone->curmaster]); + /* FALLTHROUGH */ + same_master: + if (zone->curmaster >= zone->masterscnt) { + zone->curmaster = 0; + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); + while (zone->curmaster < zone->masterscnt && + zone->mastersok[zone->curmaster]) + zone->curmaster++; + again = ISC_TRUE; + } else + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); + } else { + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH); + again = ISC_TRUE; + } + inc_stats(zone, dns_zonestatscounter_xfrfail); + break; + } + zone_settimer(zone, &now); /* - * Leave space for terminating '\0'. + * If creating the transfer object failed, zone->xfr is NULL. + * Otherwise, we are called as the done callback of a zone + * transfer object that just entered its shutting-down + * state. Since we are no longer responsible for shutting + * it down, we can detach our reference. */ - isc_buffer_init(&buffer, buf, length - 1); - if (dns_name_dynamic(&zone->origin)) - result = dns_name_totext(&zone->origin, ISC_TRUE, &buffer); - if (result != ISC_R_SUCCESS && - isc_buffer_availablelength(&buffer) >= (sizeof("") - 1)) - isc_buffer_putstr(&buffer, ""); + if (zone->xfr != NULL) + dns_xfrin_detach(&zone->xfr); - if (isc_buffer_availablelength(&buffer) > 0) - isc_buffer_putstr(&buffer, "/"); - (void)dns_rdataclass_totext(zone->rdclass, &buffer); + if (zone->tsigkey != NULL) + dns_tsigkey_detach(&zone->tsigkey); - if (zone->view != NULL && strcmp(zone->view->name, "_bind") != 0 && - strcmp(zone->view->name, "_default") != 0 && - strlen(zone->view->name) < isc_buffer_availablelength(&buffer)) { - isc_buffer_putstr(&buffer, "/"); - isc_buffer_putstr(&buffer, zone->view->name); + /* + * Handle any deferred journal compaction. + */ + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDCOMPACT)) { + result = dns_journal_compact(zone->mctx, zone->journal, + zone->compact_serial, + zone->journalsize); + switch (result) { + case ISC_R_SUCCESS: + case ISC_R_NOSPACE: + case ISC_R_NOTFOUND: + dns_zone_log(zone, ISC_LOG_DEBUG(3), + "dns_journal_compact: %s", + dns_result_totext(result)); + break; + default: + dns_zone_log(zone, ISC_LOG_ERROR, + "dns_journal_compact failed: %s", + dns_result_totext(result)); + break; + } + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDCOMPACT); } - buf[isc_buffer_usedlength(&buffer)] = '\0'; -} - -static void -zone_name_tostr(dns_zone_t *zone, char *buf, size_t length) { - isc_result_t result = ISC_R_FAILURE; - isc_buffer_t buffer; - - REQUIRE(buf != NULL); - REQUIRE(length > 1U); - /* - * Leave space for terminating '\0'. + * This transfer finishing freed up a transfer quota slot. + * Let any other zones waiting for quota have it. */ - isc_buffer_init(&buffer, buf, length - 1); - if (dns_name_dynamic(&zone->origin)) - result = dns_name_totext(&zone->origin, ISC_TRUE, &buffer); - if (result != ISC_R_SUCCESS && - isc_buffer_availablelength(&buffer) >= (sizeof("") - 1)) - isc_buffer_putstr(&buffer, ""); - - buf[isc_buffer_usedlength(&buffer)] = '\0'; -} - -static void -zone_rdclass_tostr(dns_zone_t *zone, char *buf, size_t length) { - isc_buffer_t buffer; - - REQUIRE(buf != NULL); - REQUIRE(length > 1U); + RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); + ISC_LIST_UNLINK(zone->zmgr->xfrin_in_progress, zone, statelink); + zone->statelist = NULL; + zmgr_resume_xfrs(zone->zmgr, ISC_FALSE); + RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); /* - * Leave space for terminating '\0'. + * Retry with a different server if necessary. */ - isc_buffer_init(&buffer, buf, length - 1); - (void)dns_rdataclass_totext(zone->rdclass, &buffer); + if (again && !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) + queue_soa_query(zone); - buf[isc_buffer_usedlength(&buffer)] = '\0'; + INSIST(zone->irefs > 0); + zone->irefs--; + free_needed = exit_check(zone); + UNLOCK_ZONE(zone); + if (free_needed) + zone_free(zone); } static void -zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length) { - isc_buffer_t buffer; +zone_loaddone(void *arg, isc_result_t result) { + static char me[] = "zone_loaddone"; + dns_load_t *load = arg; + dns_zone_t *zone; + isc_result_t tresult; - REQUIRE(buf != NULL); - REQUIRE(length > 1U); + REQUIRE(DNS_LOAD_VALID(load)); + zone = load->zone; + ENTER; + + tresult = dns_db_endload(load->db, &load->callbacks.add_private); + if (tresult != ISC_R_SUCCESS && + (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE)) + result = tresult; + LOCK_ZONE(load->zone); + (void)zone_postload(load->zone, load->db, load->loadtime, result); + zonemgr_putio(&load->zone->readio); + DNS_ZONE_CLRFLAG(load->zone, DNS_ZONEFLG_LOADING); /* - * Leave space for terminating '\0'. + * Leave the zone frozen if the reload fails. */ - isc_buffer_init(&buffer, buf, length - 1); - - if (zone->view == NULL) { - isc_buffer_putstr(&buffer, "_none"); - } else if (strlen(zone->view->name) - < isc_buffer_availablelength(&buffer)) { - isc_buffer_putstr(&buffer, zone->view->name); - } else { - isc_buffer_putstr(&buffer, "_toolong"); - } + if ((result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE) && + DNS_ZONE_FLAG(load->zone, DNS_ZONEFLG_THAW)) + zone->update_disabled = ISC_FALSE; + DNS_ZONE_CLRFLAG(load->zone, DNS_ZONEFLG_THAW); + UNLOCK_ZONE(load->zone); - buf[isc_buffer_usedlength(&buffer)] = '\0'; + load->magic = 0; + dns_db_detach(&load->db); + if (load->zone->lctx != NULL) + dns_loadctx_detach(&load->zone->lctx); + dns_zone_idetach(&load->zone); + isc_mem_putanddetach(&load->mctx, load, sizeof(*load)); } void -dns_zone_name(dns_zone_t *zone, char *buf, size_t length) { +dns_zone_getssutable(dns_zone_t *zone, dns_ssutable_t **table) { REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(buf != NULL); - zone_namerd_tostr(zone, buf, length); -} - -static void -notify_log(dns_zone_t *zone, int level, const char *fmt, ...) { - va_list ap; - char message[4096]; - - if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) - return; + REQUIRE(table != NULL); + REQUIRE(*table == NULL); - va_start(ap, fmt); - vsnprintf(message, sizeof(message), fmt, ap); - va_end(ap); - isc_log_write(dns_lctx, DNS_LOGCATEGORY_NOTIFY, DNS_LOGMODULE_ZONE, - level, "zone %s: %s", zone->strnamerd, message); + LOCK_ZONE(zone); + if (zone->ssutable != NULL) + dns_ssutable_attach(zone->ssutable, table); + UNLOCK_ZONE(zone); } void -dns_zone_logc(dns_zone_t *zone, isc_logcategory_t *category, - int level, const char *fmt, ...) { - va_list ap; - char message[4096]; - - if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) - return; +dns_zone_setssutable(dns_zone_t *zone, dns_ssutable_t *table) { + REQUIRE(DNS_ZONE_VALID(zone)); - va_start(ap, fmt); - vsnprintf(message, sizeof(message), fmt, ap); - va_end(ap); - isc_log_write(dns_lctx, category, DNS_LOGMODULE_ZONE, - level, "zone %s: %s", zone->strnamerd, message); + LOCK_ZONE(zone); + if (zone->ssutable != NULL) + dns_ssutable_detach(&zone->ssutable); + if (table != NULL) + dns_ssutable_attach(table, &zone->ssutable); + UNLOCK_ZONE(zone); } void -dns_zone_log(dns_zone_t *zone, int level, const char *fmt, ...) { - va_list ap; - char message[4096]; - - if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) - return; - - va_start(ap, fmt); - vsnprintf(message, sizeof(message), fmt, ap); - va_end(ap); - isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, - level, "zone %s: %s", zone->strnamerd, message); -} - -static void -zone_debuglog(dns_zone_t *zone, const char *me, int debuglevel, - const char *fmt, ...) -{ - va_list ap; - char message[4096]; - int level = ISC_LOG_DEBUG(debuglevel); - - if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) - return; +dns_zone_setsigvalidityinterval(dns_zone_t *zone, isc_uint32_t interval) { + REQUIRE(DNS_ZONE_VALID(zone)); - va_start(ap, fmt); - vsnprintf(message, sizeof(message), fmt, ap); - va_end(ap); - isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, - level, "%s: zone %s: %s", me, zone->strnamerd, message); + zone->sigvalidityinterval = interval; } -static int -message_count(dns_message_t *msg, dns_section_t section, dns_rdatatype_t type) -{ - isc_result_t result; - dns_name_t *name; - dns_rdataset_t *curr; - int count = 0; - - result = dns_message_firstname(msg, section); - while (result == ISC_R_SUCCESS) { - name = NULL; - dns_message_currentname(msg, section, &name); - - for (curr = ISC_LIST_TAIL(name->list); curr != NULL; - curr = ISC_LIST_PREV(curr, link)) { - if (curr->type == type) - count++; - } - result = dns_message_nextname(msg, section); - } +isc_uint32_t +dns_zone_getsigvalidityinterval(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); - return (count); + return (zone->sigvalidityinterval); } void -dns_zone_setmaxxfrin(dns_zone_t *zone, isc_uint32_t maxxfrin) { +dns_zone_setsigresigninginterval(dns_zone_t *zone, isc_uint32_t interval) { REQUIRE(DNS_ZONE_VALID(zone)); - zone->maxxfrin = maxxfrin; + zone->sigresigninginterval = interval; } isc_uint32_t -dns_zone_getmaxxfrin(dns_zone_t *zone) { +dns_zone_getsigresigninginterval(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); - return (zone->maxxfrin); + return (zone->sigresigninginterval); } -void -dns_zone_setmaxxfrout(dns_zone_t *zone, isc_uint32_t maxxfrout) { - REQUIRE(DNS_ZONE_VALID(zone)); - zone->maxxfrout = maxxfrout; -} +static void +queue_xfrin(dns_zone_t *zone) { + const char me[] = "queue_xfrin"; + isc_result_t result; + dns_zonemgr_t *zmgr = zone->zmgr; -isc_uint32_t -dns_zone_getmaxxfrout(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); + ENTER; - return (zone->maxxfrout); + INSIST(zone->statelist == NULL); + + RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); + ISC_LIST_APPEND(zmgr->waiting_for_xfrin, zone, statelink); + LOCK_ZONE(zone); + zone->irefs++; + UNLOCK_ZONE(zone); + zone->statelist = &zmgr->waiting_for_xfrin; + result = zmgr_start_xfrin_ifquota(zmgr, zone); + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); + + if (result == ISC_R_QUOTA) { + dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_INFO, + "zone transfer deferred due to quota"); + } else if (result != ISC_R_SUCCESS) { + dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_ERROR, + "starting zone transfer: %s", + isc_result_totext(result)); + } } -dns_zonetype_t -dns_zone_gettype(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); +/* + * This event callback is called when a zone has received + * any necessary zone transfer quota. This is the time + * to go ahead and start the transfer. + */ +static void +got_transfer_quota(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + dns_peer_t *peer = NULL; + char master[ISC_SOCKADDR_FORMATSIZE]; + char source[ISC_SOCKADDR_FORMATSIZE]; + dns_rdatatype_t xfrtype; + dns_zone_t *zone = event->ev_arg; + isc_netaddr_t masterip; + isc_sockaddr_t sourceaddr; + isc_sockaddr_t masteraddr; + isc_time_t now; + const char *soa_before = ""; + + UNUSED(task); - return (zone->type); -} + INSIST(task == zone->task); -dns_name_t * -dns_zone_getorigin(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { + result = ISC_R_CANCELED; + goto cleanup; + } - return (&zone->origin); -} + TIME_NOW(&now); -void -dns_zone_settask(dns_zone_t *zone, isc_task_t *task) { - REQUIRE(DNS_ZONE_VALID(zone)); + isc_sockaddr_format(&zone->masteraddr, master, sizeof(master)); + if (dns_zonemgr_unreachable(zone->zmgr, &zone->masteraddr, + &zone->sourceaddr, &now)) { + isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source)); + dns_zone_log(zone, ISC_LOG_INFO, + "got_transfer_quota: skipping zone transfer as " + "master %s (source %s) is unreachable (cached)", + master, source); + result = ISC_R_CANCELED; + goto cleanup; + } - LOCK_ZONE(zone); - if (zone->task != NULL) - isc_task_detach(&zone->task); - isc_task_attach(task, &zone->task); - ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); - if (zone->db != NULL) - dns_db_settask(zone->db, zone->task); - ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); - UNLOCK_ZONE(zone); -} + isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); + (void)dns_peerlist_peerbyaddr(zone->view->peers, &masterip, &peer); -void -dns_zone_gettask(dns_zone_t *zone, isc_task_t **target) { - REQUIRE(DNS_ZONE_VALID(zone)); - isc_task_attach(zone->task, target); -} + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) + soa_before = "SOA before "; + /* + * Decide whether we should request IXFR or AXFR. + */ + if (zone->db == NULL) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "no database exists yet, requesting AXFR of " + "initial version from %s", master); + xfrtype = dns_rdatatype_axfr; + } else if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS)) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), "ixfr-from-differences " + "set, requesting %sAXFR from %s", soa_before, + master); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) + xfrtype = dns_rdatatype_soa; + else + xfrtype = dns_rdatatype_axfr; + } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "forced reload, requesting AXFR of " + "initial version from %s", master); + xfrtype = dns_rdatatype_axfr; + } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLAG_NOIXFR)) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "retrying with AXFR from %s due to " + "previous IXFR failure", master); + xfrtype = dns_rdatatype_axfr; + LOCK_ZONE(zone); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLAG_NOIXFR); + UNLOCK_ZONE(zone); + } else { + isc_boolean_t use_ixfr = ISC_TRUE; + if (peer != NULL && + dns_peer_getrequestixfr(peer, &use_ixfr) == + ISC_R_SUCCESS) { + ; /* Using peer setting */ + } else { + use_ixfr = zone->view->requestixfr; + } + if (use_ixfr == ISC_FALSE) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "IXFR disabled, requesting %sAXFR from %s", + soa_before, master); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) + xfrtype = dns_rdatatype_soa; + else + xfrtype = dns_rdatatype_axfr; + } else { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "requesting IXFR from %s", master); + xfrtype = dns_rdatatype_ixfr; + } + } -void -dns_zone_setidlein(dns_zone_t *zone, isc_uint32_t idlein) { - REQUIRE(DNS_ZONE_VALID(zone)); + /* + * Determine if we should attempt to sign the request with TSIG. + */ + result = ISC_R_NOTFOUND; + /* + * First, look for a tsig key in the master statement, then + * try for a server key. + */ + if ((zone->masterkeynames != NULL) && + (zone->masterkeynames[zone->curmaster] != NULL)) { + dns_view_t *view = dns_zone_getview(zone); + dns_name_t *keyname = zone->masterkeynames[zone->curmaster]; + result = dns_view_gettsig(view, keyname, &zone->tsigkey); + } + if (zone->tsigkey == NULL) + result = dns_view_getpeertsig(zone->view, &masterip, + &zone->tsigkey); - if (idlein == 0) - idlein = DNS_DEFAULT_IDLEIN; - zone->idlein = idlein; -} + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { + dns_zone_log(zone, ISC_LOG_ERROR, + "could not get TSIG key for zone transfer: %s", + isc_result_totext(result)); + } -isc_uint32_t -dns_zone_getidlein(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); + LOCK_ZONE(zone); + masteraddr = zone->masteraddr; + sourceaddr = zone->sourceaddr; + UNLOCK_ZONE(zone); + INSIST(isc_sockaddr_pf(&masteraddr) == isc_sockaddr_pf(&sourceaddr)); + result = dns_xfrin_create2(zone, xfrtype, &masteraddr, &sourceaddr, + zone->tsigkey, zone->mctx, + zone->zmgr->timermgr, zone->zmgr->socketmgr, + zone->task, zone_xfrdone, &zone->xfr); + if (result == ISC_R_SUCCESS) { + LOCK_ZONE(zone); + if (xfrtype == dns_rdatatype_axfr) { + if (isc_sockaddr_pf(&masteraddr) == PF_INET) + inc_stats(zone, dns_zonestatscounter_axfrreqv4); + else + inc_stats(zone, dns_zonestatscounter_axfrreqv6); + } else if (xfrtype == dns_rdatatype_ixfr) { + if (isc_sockaddr_pf(&masteraddr) == PF_INET) + inc_stats(zone, dns_zonestatscounter_ixfrreqv4); + else + inc_stats(zone, dns_zonestatscounter_ixfrreqv6); + } + UNLOCK_ZONE(zone); + } + cleanup: + /* + * Any failure in this function is handled like a failed + * zone transfer. This ensures that we get removed from + * zmgr->xfrin_in_progress. + */ + if (result != ISC_R_SUCCESS) + zone_xfrdone(zone, result); - return (zone->idlein); + isc_event_free(&event); } -void -dns_zone_setidleout(dns_zone_t *zone, isc_uint32_t idleout) { - REQUIRE(DNS_ZONE_VALID(zone)); - - zone->idleout = idleout; -} +/* + * Update forwarding support. + */ -isc_uint32_t -dns_zone_getidleout(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); +static void +forward_destroy(dns_forward_t *forward) { - return (zone->idleout); + forward->magic = 0; + if (forward->request != NULL) + dns_request_destroy(&forward->request); + if (forward->msgbuf != NULL) + isc_buffer_free(&forward->msgbuf); + if (forward->zone != NULL) + dns_zone_idetach(&forward->zone); + isc_mem_putanddetach(&forward->mctx, forward, sizeof(*forward)); } -static void -notify_done(isc_task_t *task, isc_event_t *event) { - dns_requestevent_t *revent = (dns_requestevent_t *)event; - dns_notify_t *notify; +static isc_result_t +sendtomaster(dns_forward_t *forward) { isc_result_t result; - dns_message_t *message = NULL; - isc_buffer_t buf; - char rcode[128]; - char addrbuf[ISC_SOCKADDR_FORMATSIZE]; - - UNUSED(task); - - notify = event->ev_arg; - REQUIRE(DNS_NOTIFY_VALID(notify)); - INSIST(task == notify->zone->task); - - isc_buffer_init(&buf, rcode, sizeof(rcode)); - isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf)); + isc_sockaddr_t src; - result = revent->result; - if (result == ISC_R_SUCCESS) - result = dns_message_create(notify->zone->mctx, - DNS_MESSAGE_INTENTPARSE, &message); - if (result == ISC_R_SUCCESS) - result = dns_request_getresponse(revent->request, message, - DNS_MESSAGEPARSE_PRESERVEORDER); - if (result == ISC_R_SUCCESS) - result = dns_rcode_totext(message->rcode, &buf); - if (result == ISC_R_SUCCESS) - notify_log(notify->zone, ISC_LOG_DEBUG(3), - "notify response from %s: %.*s", - addrbuf, (int)buf.used, rcode); - else - notify_log(notify->zone, ISC_LOG_DEBUG(2), - "notify to %s failed: %s", addrbuf, - dns_result_totext(result)); + LOCK_ZONE(forward->zone); + if (forward->which >= forward->zone->masterscnt) { + UNLOCK_ZONE(forward->zone); + return (ISC_R_NOMORE); + } + forward->addr = forward->zone->masters[forward->which]; /* - * Old bind's return formerr if they see a soa record. Retry w/o - * the soa if we see a formerr and had sent a SOA. + * Always use TCP regardless of whether the original update + * used TCP. + * XXX The timeout may but a bit small if we are far down a + * transfer graph and the master has to try several masters. */ - isc_event_free(&event); - if (message != NULL && message->rcode == dns_rcode_formerr && - (notify->flags & DNS_NOTIFY_NOSOA) == 0) { - notify->flags |= DNS_NOTIFY_NOSOA; - dns_request_destroy(¬ify->request); - result = notify_send_queue(notify); - if (result != ISC_R_SUCCESS) - notify_destroy(notify, ISC_FALSE); - } else { - if (result == ISC_R_TIMEDOUT) - notify_log(notify->zone, ISC_LOG_DEBUG(1), - "notify to %s: retries exceeded", addrbuf); - notify_destroy(notify, ISC_FALSE); + switch (isc_sockaddr_pf(&forward->addr)) { + case PF_INET: + src = forward->zone->xfrsource4; + break; + case PF_INET6: + src = forward->zone->xfrsource6; + break; + default: + result = ISC_R_NOTIMPLEMENTED; + goto unlock; } - if (message != NULL) - dns_message_destroy(&message); + result = dns_request_createraw(forward->zone->view->requestmgr, + forward->msgbuf, + &src, &forward->addr, + DNS_REQUESTOPT_TCP, 15 /* XXX */, + forward->zone->task, + forward_callback, forward, + &forward->request); + unlock: + UNLOCK_ZONE(forward->zone); + return (result); } -isc_result_t -dns_zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { +static void +forward_callback(isc_task_t *task, isc_event_t *event) { + const char me[] = "forward_callback"; + dns_requestevent_t *revent = (dns_requestevent_t *)event; + dns_message_t *msg = NULL; + char master[ISC_SOCKADDR_FORMATSIZE]; isc_result_t result; + dns_forward_t *forward; + dns_zone_t *zone; - REQUIRE(DNS_ZONE_VALID(zone)); - LOCK_ZONE(zone); - ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); - result = zone_replacedb(zone, db, dump); - ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); - UNLOCK_ZONE(zone); - return (result); -} + UNUSED(task); -static isc_result_t -zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { - dns_dbversion_t *ver; - isc_result_t result; - unsigned int soacount = 0; - unsigned int nscount = 0; + forward = revent->ev_arg; + INSIST(DNS_FORWARD_VALID(forward)); + zone = forward->zone; + INSIST(DNS_ZONE_VALID(zone)); - /* - * 'zone' and 'zonedb' locked by caller. - */ - REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(LOCKED_ZONE(zone)); + ENTER; - result = zone_get_from_db(zone, db, &nscount, &soacount, - NULL, NULL, NULL, NULL, NULL, NULL); - if (result == ISC_R_SUCCESS) { - if (soacount != 1) { - dns_zone_log(zone, ISC_LOG_ERROR, - "has %d SOA records", soacount); - result = DNS_R_BADZONE; - } - if (nscount == 0) { - dns_zone_log(zone, ISC_LOG_ERROR, "has no NS records"); - result = DNS_R_BADZONE; - } - if (result != ISC_R_SUCCESS) - return (result); - } else { - dns_zone_log(zone, ISC_LOG_ERROR, - "retrieving SOA and NS records failed: %s", - dns_result_totext(result)); - return (result); + isc_sockaddr_format(&forward->addr, master, sizeof(master)); + + if (revent->result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_INFO, + "could not forward dynamic update to %s: %s", + master, dns_result_totext(revent->result)); + goto next_master; } - result = check_nsec3param(zone, db); + result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTPARSE, &msg); if (result != ISC_R_SUCCESS) - return (result); + goto next_master; - ver = NULL; - dns_db_currentversion(db, &ver); + result = dns_request_getresponse(revent->request, msg, + DNS_MESSAGEPARSE_PRESERVEORDER | + DNS_MESSAGEPARSE_CLONEBUFFER); + if (result != ISC_R_SUCCESS) + goto next_master; + switch (msg->rcode) { /* - * The initial version of a slave zone is always dumped; - * subsequent versions may be journaled instead if this - * is enabled in the configuration. + * Pass these rcodes back to client. */ - if (zone->db != NULL && zone->journal != NULL && - DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) && - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) { - isc_uint32_t serial, oldserial; - - dns_zone_log(zone, ISC_LOG_DEBUG(3), "generating diffs"); + case dns_rcode_noerror: + case dns_rcode_yxdomain: + case dns_rcode_yxrrset: + case dns_rcode_nxrrset: + case dns_rcode_refused: + case dns_rcode_nxdomain: + break; - result = dns_db_getsoaserial(db, ver, &serial); - if (result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_ERROR, - "ixfr-from-differences: unable to get " - "new serial"); - goto fail; - } + /* These should not occur if the masters/zone are valid. */ + case dns_rcode_notzone: + case dns_rcode_notauth: { + char rcode[128]; + isc_buffer_t rb; - /* - * This is checked in zone_postload() for master zones. - */ - result = zone_get_from_db(zone, zone->db, NULL, NULL, - &oldserial, NULL, NULL, NULL, NULL, - NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - if (zone->type == dns_zone_slave && - !isc_serial_gt(serial, oldserial)) { - isc_uint32_t serialmin, serialmax; - serialmin = (oldserial + 1) & 0xffffffffU; - serialmax = (oldserial + 0x7fffffffU) & 0xffffffffU; - dns_zone_log(zone, ISC_LOG_ERROR, - "ixfr-from-differences: failed: " - "new serial (%u) out of range [%u - %u]", - serial, serialmin, serialmax); - result = ISC_R_RANGE; - goto fail; - } + isc_buffer_init(&rb, rcode, sizeof(rcode)); + (void)dns_rcode_totext(msg->rcode, &rb); + dns_zone_log(zone, ISC_LOG_WARNING, + "forwarding dynamic update: " + "unexpected response: master %s returned: %.*s", + master, (int)rb.used, rcode); + goto next_master; + } - result = dns_db_diff(zone->mctx, db, ver, zone->db, NULL, - zone->journal); - if (result != ISC_R_SUCCESS) - goto fail; - if (dump) - zone_needdump(zone, DNS_DUMP_DELAY); - else if (zone->journalsize != -1) { - result = dns_journal_compact(zone->mctx, zone->journal, - serial, zone->journalsize); - switch (result) { - case ISC_R_SUCCESS: - case ISC_R_NOSPACE: - case ISC_R_NOTFOUND: - dns_zone_log(zone, ISC_LOG_DEBUG(3), - "dns_journal_compact: %s", - dns_result_totext(result)); - break; - default: - dns_zone_log(zone, ISC_LOG_ERROR, - "dns_journal_compact failed: %s", - dns_result_totext(result)); - break; - } - } - } else { - if (dump && zone->masterfile != NULL) { - isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), - "dumping new zone version"); - result = dns_db_dump2(db, ver, zone->masterfile, - zone->masterformat); - if (result != ISC_R_SUCCESS) - goto fail; + /* Try another server for these rcodes. */ + case dns_rcode_formerr: + case dns_rcode_servfail: + case dns_rcode_notimp: + case dns_rcode_badvers: + default: + goto next_master; + } - /* - * Update the time the zone was updated, so - * dns_zone_load can avoid loading it when - * the server is reloaded. If isc_time_now - * fails for some reason, all that happens is - * the timestamp is not updated. - */ - TIME_NOW(&zone->loadtime); - } + /* call callback */ + (forward->callback)(forward->callback_arg, ISC_R_SUCCESS, msg); + msg = NULL; + dns_request_destroy(&forward->request); + forward_destroy(forward); + isc_event_free(&event); + return; - if (dump && zone->journal != NULL) { - /* - * The in-memory database just changed, and - * because 'dump' is set, it didn't change by - * being loaded from disk. Also, we have not - * journaled diffs for this change. - * Therefore, the on-disk journal is missing - * the deltas for this change. Since it can - * no longer be used to bring the zone - * up-to-date, it is useless and should be - * removed. - */ - isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), - "removing journal file"); - if (remove(zone->journal) < 0 && errno != ENOENT) { - char strbuf[ISC_STRERRORSIZE]; - isc__strerror(errno, strbuf, sizeof(strbuf)); - isc_log_write(dns_lctx, - DNS_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_ZONE, - ISC_LOG_WARNING, - "unable to remove journal " - "'%s': '%s'", - zone->journal, strbuf); - } - } + next_master: + if (msg != NULL) + dns_message_destroy(&msg); + isc_event_free(&event); + forward->which++; + dns_request_destroy(&forward->request); + result = sendtomaster(forward); + if (result != ISC_R_SUCCESS) { + /* call callback */ + dns_zone_log(zone, ISC_LOG_DEBUG(3), + "exhausted dynamic update forwarder list"); + (forward->callback)(forward->callback_arg, result, NULL); + forward_destroy(forward); } +} + +isc_result_t +dns_zone_forwardupdate(dns_zone_t *zone, dns_message_t *msg, + dns_updatecallback_t callback, void *callback_arg) +{ + dns_forward_t *forward; + isc_result_t result; + isc_region_t *mr; + + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(msg != NULL); + REQUIRE(callback != NULL); + + forward = isc_mem_get(zone->mctx, sizeof(*forward)); + if (forward == NULL) + return (ISC_R_NOMEMORY); + + forward->request = NULL; + forward->zone = NULL; + forward->msgbuf = NULL; + forward->which = 0; + forward->mctx = 0; + forward->callback = callback; + forward->callback_arg = callback_arg; + forward->magic = FORWARD_MAGIC; - dns_db_closeversion(db, &ver, ISC_FALSE); + mr = dns_message_getrawmessage(msg); + if (mr == NULL) { + result = ISC_R_UNEXPECTEDEND; + goto cleanup; + } - isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), - "replacing zone database"); + result = isc_buffer_allocate(zone->mctx, &forward->msgbuf, mr->length); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = isc_buffer_copyregion(forward->msgbuf, mr); + if (result != ISC_R_SUCCESS) + goto cleanup; - if (zone->db != NULL) - zone_detachdb(zone); - zone_attachdb(zone, db); - dns_db_settask(zone->db, zone->task); - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY); - return (ISC_R_SUCCESS); + isc_mem_attach(zone->mctx, &forward->mctx); + dns_zone_iattach(zone, &forward->zone); + result = sendtomaster(forward); - fail: - dns_db_closeversion(db, &ver, ISC_FALSE); + cleanup: + if (result != ISC_R_SUCCESS) { + forward_destroy(forward); + } return (result); } -/* The caller must hold the dblock as a writer. */ -static inline void -zone_attachdb(dns_zone_t *zone, dns_db_t *db) { - REQUIRE(zone->db == NULL && db != NULL); +isc_result_t +dns_zone_next(dns_zone_t *zone, dns_zone_t **next) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(next != NULL && *next == NULL); - dns_db_attach(db, &zone->db); - if (zone->acache != NULL) { - isc_result_t result; - result = dns_acache_setdb(zone->acache, db); - if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "dns_acache_setdb() failed: %s", - isc_result_totext(result)); - } - } + *next = ISC_LIST_NEXT(zone, link); + if (*next == NULL) + return (ISC_R_NOMORE); + else + return (ISC_R_SUCCESS); } -/* The caller must hold the dblock as a writer. */ -static inline void -zone_detachdb(dns_zone_t *zone) { - REQUIRE(zone->db != NULL); +isc_result_t +dns_zone_first(dns_zonemgr_t *zmgr, dns_zone_t **first) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + REQUIRE(first != NULL && *first == NULL); - if (zone->acache != NULL) - (void)dns_acache_putdb(zone->acache, zone->db); - dns_db_detach(&zone->db); + *first = ISC_LIST_HEAD(zmgr->zones); + if (*first == NULL) + return (ISC_R_NOMORE); + else + return (ISC_R_SUCCESS); } -static void -zone_xfrdone(dns_zone_t *zone, isc_result_t result) { - isc_time_t now; - isc_boolean_t again = ISC_FALSE; - unsigned int soacount; - unsigned int nscount; - isc_uint32_t serial, refresh, retry, expire, minimum; - isc_result_t xfrresult = result; - isc_boolean_t free_needed; +/*** + *** Zone manager. + ***/ - REQUIRE(DNS_ZONE_VALID(zone)); +isc_result_t +dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, + dns_zonemgr_t **zmgrp) +{ + dns_zonemgr_t *zmgr; + isc_result_t result; + isc_interval_t interval; - dns_zone_log(zone, ISC_LOG_DEBUG(1), - "zone transfer finished: %s", dns_result_totext(result)); + zmgr = isc_mem_get(mctx, sizeof(*zmgr)); + if (zmgr == NULL) + return (ISC_R_NOMEMORY); + zmgr->mctx = NULL; + zmgr->refs = 1; + isc_mem_attach(mctx, &zmgr->mctx); + zmgr->taskmgr = taskmgr; + zmgr->timermgr = timermgr; + zmgr->socketmgr = socketmgr; + zmgr->zonetasks = NULL; + zmgr->task = NULL; + zmgr->rl = NULL; + ISC_LIST_INIT(zmgr->zones); + ISC_LIST_INIT(zmgr->waiting_for_xfrin); + ISC_LIST_INIT(zmgr->xfrin_in_progress); + memset(zmgr->unreachable, 0, sizeof(zmgr->unreachable)); + result = isc_rwlock_init(&zmgr->rwlock, 0, 0); + if (result != ISC_R_SUCCESS) + goto free_mem; - LOCK_ZONE(zone); - INSIST((zone->flags & DNS_ZONEFLG_REFRESH) != 0); - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR); + zmgr->transfersin = 10; + zmgr->transfersperns = 2; - TIME_NOW(&now); - switch (result) { - case ISC_R_SUCCESS: - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); - /*FALLTHROUGH*/ - case DNS_R_UPTODATE: - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_FORCEXFER); - /* - * Has the zone expired underneath us? - */ - ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); - if (zone->db == NULL) { - ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); - goto same_master; - } + /* Create the zone task pool. */ + result = isc_taskpool_create(taskmgr, mctx, + 8 /* XXX */, 2, &zmgr->zonetasks); + if (result != ISC_R_SUCCESS) + goto free_rwlock; - /* - * Update the zone structure's data from the actual - * SOA received. - */ - nscount = 0; - soacount = 0; - INSIST(zone->db != NULL); - result = zone_get_from_db(zone, zone->db, &nscount, - &soacount, &serial, &refresh, - &retry, &expire, &minimum, NULL); - ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); - if (result == ISC_R_SUCCESS) { - if (soacount != 1) - dns_zone_log(zone, ISC_LOG_ERROR, - "transferred zone " - "has %d SOA record%s", soacount, - (soacount != 0) ? "s" : ""); - if (nscount == 0) { - dns_zone_log(zone, ISC_LOG_ERROR, - "transferred zone " - "has no NS records"); - if (DNS_ZONE_FLAG(zone, - DNS_ZONEFLG_HAVETIMERS)) { - zone->refresh = DNS_ZONE_DEFAULTREFRESH; - zone->retry = DNS_ZONE_DEFAULTRETRY; - } - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HAVETIMERS); - zone_unload(zone); - goto next_master; - } - zone->refresh = RANGE(refresh, zone->minrefresh, - zone->maxrefresh); - zone->retry = RANGE(retry, zone->minretry, - zone->maxretry); - zone->expire = RANGE(expire, - zone->refresh + zone->retry, - DNS_MAX_EXPIRE); - zone->minimum = minimum; - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS); - } + /* Create a single task for queueing of SOA queries. */ + result = isc_task_create(taskmgr, 1, &zmgr->task); + if (result != ISC_R_SUCCESS) + goto free_taskpool; + isc_task_setname(zmgr->task, "zmgr", zmgr); + result = isc_ratelimiter_create(mctx, timermgr, zmgr->task, + &zmgr->rl); + if (result != ISC_R_SUCCESS) + goto free_task; + /* default to 20 refresh queries / notifies per second. */ + isc_interval_set(&interval, 0, 1000000000/2); + result = isc_ratelimiter_setinterval(zmgr->rl, &interval); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + isc_ratelimiter_setpertic(zmgr->rl, 10); - /* - * Set our next update/expire times. - */ - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDREFRESH)) { - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDREFRESH); - zone->refreshtime = now; - DNS_ZONE_TIME_ADD(&now, zone->expire, - &zone->expiretime); - } else { - DNS_ZONE_JITTER_ADD(&now, zone->refresh, - &zone->refreshtime); - DNS_ZONE_TIME_ADD(&now, zone->expire, - &zone->expiretime); - } - if (result == ISC_R_SUCCESS && xfrresult == ISC_R_SUCCESS) { - char buf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''")]; - if (zone->tsigkey != NULL) { - char namebuf[DNS_NAME_FORMATSIZE]; - dns_name_format(&zone->tsigkey->name, namebuf, - sizeof(namebuf)); - snprintf(buf, sizeof(buf), ": TSIG '%s'", - namebuf); - } else - buf[0] = '\0'; - dns_zone_log(zone, ISC_LOG_INFO, - "transferred serial %u%s", - serial, buf); - } + zmgr->iolimit = 1; + zmgr->ioactive = 0; + ISC_LIST_INIT(zmgr->high); + ISC_LIST_INIT(zmgr->low); + + result = isc_mutex_init(&zmgr->iolock); + if (result != ISC_R_SUCCESS) + goto free_rl; + + zmgr->magic = ZONEMGR_MAGIC; + + *zmgrp = zmgr; + return (ISC_R_SUCCESS); + +#if 0 + free_iolock: + DESTROYLOCK(&zmgr->iolock); +#endif + free_rl: + isc_ratelimiter_detach(&zmgr->rl); + free_task: + isc_task_detach(&zmgr->task); + free_taskpool: + isc_taskpool_destroy(&zmgr->zonetasks); + free_rwlock: + isc_rwlock_destroy(&zmgr->rwlock); + free_mem: + isc_mem_put(zmgr->mctx, zmgr, sizeof(*zmgr)); + isc_mem_detach(&mctx); + return (result); +} - /* - * This is not necessary if we just performed a AXFR - * however it is necessary for an IXFR / UPTODATE and - * won't hurt with an AXFR. - */ - if (zone->masterfile != NULL || zone->journal != NULL) { - result = ISC_R_FAILURE; - if (zone->journal != NULL) - result = isc_file_settime(zone->journal, &now); - if (result != ISC_R_SUCCESS && - zone->masterfile != NULL) - result = isc_file_settime(zone->masterfile, - &now); - /* Someone removed the file from underneath us! */ - if (result == ISC_R_FILENOTFOUND && - zone->masterfile != NULL) - zone_needdump(zone, DNS_DUMP_DELAY); - else if (result != ISC_R_SUCCESS) - dns_zone_log(zone, ISC_LOG_ERROR, - "transfer: could not set file " - "modification time of '%s': %s", - zone->masterfile, - dns_result_totext(result)); - } +isc_result_t +dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) { + isc_result_t result; - inc_stats(zone, dns_zonestatscounter_xfrsuccess); - break; + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - case DNS_R_BADIXFR: - /* Force retry with AXFR. */ - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLAG_NOIXFR); - goto same_master; + RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); + LOCK_ZONE(zone); + REQUIRE(zone->task == NULL); + REQUIRE(zone->timer == NULL); + REQUIRE(zone->zmgr == NULL); - default: - next_master: - /* - * Skip to next failed / untried master. - */ - do { - zone->curmaster++; - } while (zone->curmaster < zone->masterscnt && - zone->mastersok[zone->curmaster]); - /* FALLTHROUGH */ - same_master: - if (zone->curmaster >= zone->masterscnt) { - zone->curmaster = 0; - if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_USEALTXFRSRC) && - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEALTXFRSRC)) { - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH); - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); - while (zone->curmaster < zone->masterscnt && - zone->mastersok[zone->curmaster]) - zone->curmaster++; - again = ISC_TRUE; - } else - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_USEALTXFRSRC); - } else { - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH); - again = ISC_TRUE; - } - inc_stats(zone, dns_zonestatscounter_xfrfail); - break; - } - zone_settimer(zone, &now); + isc_taskpool_gettask(zmgr->zonetasks, + dns_name_hash(dns_zone_getorigin(zone), + ISC_FALSE), + &zone->task); /* - * If creating the transfer object failed, zone->xfr is NULL. - * Otherwise, we are called as the done callback of a zone - * transfer object that just entered its shutting-down - * state. Since we are no longer responsible for shutting - * it down, we can detach our reference. + * Set the task name. The tag will arbitrarily point to one + * of the zones sharing the task (in practice, the one + * to be managed last). */ - if (zone->xfr != NULL) - dns_xfrin_detach(&zone->xfr); + isc_task_setname(zone->task, "zone", zone); - if (zone->tsigkey != NULL) - dns_tsigkey_detach(&zone->tsigkey); + result = isc_timer_create(zmgr->timermgr, isc_timertype_inactive, + NULL, NULL, + zone->task, zone_timer, zone, + &zone->timer); - /* - * Handle any deferred journal compaction. - */ - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDCOMPACT)) { - result = dns_journal_compact(zone->mctx, zone->journal, - zone->compact_serial, - zone->journalsize); - switch (result) { - case ISC_R_SUCCESS: - case ISC_R_NOSPACE: - case ISC_R_NOTFOUND: - dns_zone_log(zone, ISC_LOG_DEBUG(3), - "dns_journal_compact: %s", - dns_result_totext(result)); - break; - default: - dns_zone_log(zone, ISC_LOG_ERROR, - "dns_journal_compact failed: %s", - dns_result_totext(result)); - break; - } - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDCOMPACT); - } + if (result != ISC_R_SUCCESS) + goto cleanup_task; /* - * This transfer finishing freed up a transfer quota slot. - * Let any other zones waiting for quota have it. + * The timer "holds" a iref. */ - RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); - ISC_LIST_UNLINK(zone->zmgr->xfrin_in_progress, zone, statelink); - zone->statelist = NULL; - zmgr_resume_xfrs(zone->zmgr, ISC_FALSE); - RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write); + zone->irefs++; + INSIST(zone->irefs != 0); - /* - * Retry with a different server if necessary. - */ - if (again && !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) - queue_soa_query(zone); + ISC_LIST_APPEND(zmgr->zones, zone, link); + zone->zmgr = zmgr; + zmgr->refs++; - INSIST(zone->irefs > 0); - zone->irefs--; - free_needed = exit_check(zone); + goto unlock; + + cleanup_task: + isc_task_detach(&zone->task); + + unlock: UNLOCK_ZONE(zone); - if (free_needed) - zone_free(zone); + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); + return (result); } -static void -zone_loaddone(void *arg, isc_result_t result) { - static char me[] = "zone_loaddone"; - dns_load_t *load = arg; - dns_zone_t *zone; - isc_result_t tresult; +void +dns_zonemgr_releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) { + isc_boolean_t free_now = ISC_FALSE; - REQUIRE(DNS_LOAD_VALID(load)); - zone = load->zone; + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + REQUIRE(zone->zmgr == zmgr); - ENTER; + RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); + LOCK_ZONE(zone); - tresult = dns_db_endload(load->db, &load->callbacks.add_private); - if (tresult != ISC_R_SUCCESS && - (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE)) - result = tresult; + ISC_LIST_UNLINK(zmgr->zones, zone, link); + zone->zmgr = NULL; + zmgr->refs--; + if (zmgr->refs == 0) + free_now = ISC_TRUE; + + UNLOCK_ZONE(zone); + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); + + if (free_now) + zonemgr_free(zmgr); + ENSURE(zone->zmgr == NULL); +} + +void +dns_zonemgr_attach(dns_zonemgr_t *source, dns_zonemgr_t **target) { + REQUIRE(DNS_ZONEMGR_VALID(source)); + REQUIRE(target != NULL && *target == NULL); + + RWLOCK(&source->rwlock, isc_rwlocktype_write); + REQUIRE(source->refs > 0); + source->refs++; + INSIST(source->refs > 0); + RWUNLOCK(&source->rwlock, isc_rwlocktype_write); + *target = source; +} + +void +dns_zonemgr_detach(dns_zonemgr_t **zmgrp) { + dns_zonemgr_t *zmgr; + isc_boolean_t free_now = ISC_FALSE; + + REQUIRE(zmgrp != NULL); + zmgr = *zmgrp; + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); + zmgr->refs--; + if (zmgr->refs == 0) + free_now = ISC_TRUE; + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); + + if (free_now) + zonemgr_free(zmgr); +} + +isc_result_t +dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr) { + dns_zone_t *p; + + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + RWLOCK(&zmgr->rwlock, isc_rwlocktype_read); + for (p = ISC_LIST_HEAD(zmgr->zones); + p != NULL; + p = ISC_LIST_NEXT(p, link)) + { + dns_zone_maintenance(p); + } + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); - LOCK_ZONE(load->zone); - (void)zone_postload(load->zone, load->db, load->loadtime, result); - zonemgr_putio(&load->zone->readio); - DNS_ZONE_CLRFLAG(load->zone, DNS_ZONEFLG_LOADING); /* - * Leave the zone frozen if the reload fails. + * Recent configuration changes may have increased the + * amount of available transfers quota. Make sure any + * transfers currently blocked on quota get started if + * possible. */ - if ((result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE) && - DNS_ZONE_FLAG(load->zone, DNS_ZONEFLG_THAW)) - zone->update_disabled = ISC_FALSE; - DNS_ZONE_CLRFLAG(load->zone, DNS_ZONEFLG_THAW); - UNLOCK_ZONE(load->zone); + RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); + zmgr_resume_xfrs(zmgr, ISC_TRUE); + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); + return (ISC_R_SUCCESS); +} - load->magic = 0; - dns_db_detach(&load->db); - if (load->zone->lctx != NULL) - dns_loadctx_detach(&load->zone->lctx); - dns_zone_idetach(&load->zone); - isc_mem_putanddetach(&load->mctx, load, sizeof(*load)); +void +dns_zonemgr_resumexfrs(dns_zonemgr_t *zmgr) { + + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); + zmgr_resume_xfrs(zmgr, ISC_TRUE); + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); } void -dns_zone_getssutable(dns_zone_t *zone, dns_ssutable_t **table) { - REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(table != NULL); - REQUIRE(*table == NULL); +dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - LOCK_ZONE(zone); - if (zone->ssutable != NULL) - dns_ssutable_attach(zone->ssutable, table); - UNLOCK_ZONE(zone); + isc_ratelimiter_shutdown(zmgr->rl); + + if (zmgr->task != NULL) + isc_task_destroy(&zmgr->task); + if (zmgr->zonetasks != NULL) + isc_taskpool_destroy(&zmgr->zonetasks); } -void -dns_zone_setssutable(dns_zone_t *zone, dns_ssutable_t *table) { - REQUIRE(DNS_ZONE_VALID(zone)); +static void +zonemgr_free(dns_zonemgr_t *zmgr) { + isc_mem_t *mctx; - LOCK_ZONE(zone); - if (zone->ssutable != NULL) - dns_ssutable_detach(&zone->ssutable); - if (table != NULL) - dns_ssutable_attach(table, &zone->ssutable); - UNLOCK_ZONE(zone); + INSIST(zmgr->refs == 0); + INSIST(ISC_LIST_EMPTY(zmgr->zones)); + + zmgr->magic = 0; + + DESTROYLOCK(&zmgr->iolock); + isc_ratelimiter_detach(&zmgr->rl); + + isc_rwlock_destroy(&zmgr->rwlock); + mctx = zmgr->mctx; + isc_mem_put(zmgr->mctx, zmgr, sizeof(*zmgr)); + isc_mem_detach(&mctx); } void -dns_zone_setsigvalidityinterval(dns_zone_t *zone, isc_uint32_t interval) { - REQUIRE(DNS_ZONE_VALID(zone)); +dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, isc_uint32_t value) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - zone->sigvalidityinterval = interval; + zmgr->transfersin = value; } isc_uint32_t -dns_zone_getsigvalidityinterval(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); +dns_zonemgr_getttransfersin(dns_zonemgr_t *zmgr) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - return (zone->sigvalidityinterval); + return (zmgr->transfersin); } void -dns_zone_setsigresigninginterval(dns_zone_t *zone, isc_uint32_t interval) { - REQUIRE(DNS_ZONE_VALID(zone)); +dns_zonemgr_settransfersperns(dns_zonemgr_t *zmgr, isc_uint32_t value) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - zone->sigresigninginterval = interval; + zmgr->transfersperns = value; } isc_uint32_t -dns_zone_getsigresigninginterval(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); +dns_zonemgr_getttransfersperns(dns_zonemgr_t *zmgr) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - return (zone->sigresigninginterval); + return (zmgr->transfersperns); } +/* + * Try to start a new incoming zone transfer to fill a quota + * slot that was just vacated. + * + * Requires: + * The zone manager is locked by the caller. + */ static void -queue_xfrin(dns_zone_t *zone) { - const char me[] = "queue_xfrin"; - isc_result_t result; - dns_zonemgr_t *zmgr = zone->zmgr; - - ENTER; - - INSIST(zone->statelist == NULL); - - RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); - ISC_LIST_APPEND(zmgr->waiting_for_xfrin, zone, statelink); - LOCK_ZONE(zone); - zone->irefs++; - UNLOCK_ZONE(zone); - zone->statelist = &zmgr->waiting_for_xfrin; - result = zmgr_start_xfrin_ifquota(zmgr, zone); - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); +zmgr_resume_xfrs(dns_zonemgr_t *zmgr, isc_boolean_t multi) { + dns_zone_t *zone; + dns_zone_t *next; - if (result == ISC_R_QUOTA) { - dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_INFO, - "zone transfer deferred due to quota"); - } else if (result != ISC_R_SUCCESS) { - dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_ERROR, - "starting zone transfer: %s", - isc_result_totext(result)); + for (zone = ISC_LIST_HEAD(zmgr->waiting_for_xfrin); + zone != NULL; + zone = next) + { + isc_result_t result; + next = ISC_LIST_NEXT(zone, statelink); + result = zmgr_start_xfrin_ifquota(zmgr, zone); + if (result == ISC_R_SUCCESS) { + if (multi) + continue; + /* + * We successfully filled the slot. We're done. + */ + break; + } else if (result == ISC_R_QUOTA) { + /* + * Not enough quota. This is probably the per-server + * quota, because we usually get called when a unit of + * global quota has just been freed. Try the next + * zone, it may succeed if it uses another master. + */ + continue; + } else { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "starting zone transfer: %s", + isc_result_totext(result)); + break; + } } } /* - * This event callback is called when a zone has received - * any necessary zone transfer quota. This is the time - * to go ahead and start the transfer. + * Try to start an incoming zone transfer for 'zone', quota permitting. + * + * Requires: + * The zone manager is locked by the caller. + * + * Returns: + * ISC_R_SUCCESS There was enough quota and we attempted to + * start a transfer. zone_xfrdone() has been or will + * be called. + * ISC_R_QUOTA Not enough quota. + * Others Failure. */ -static void -got_transfer_quota(isc_task_t *task, isc_event_t *event) { - isc_result_t result; +static isc_result_t +zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) { dns_peer_t *peer = NULL; - char master[ISC_SOCKADDR_FORMATSIZE]; - char source[ISC_SOCKADDR_FORMATSIZE]; - dns_rdatatype_t xfrtype; - dns_zone_t *zone = event->ev_arg; isc_netaddr_t masterip; - isc_sockaddr_t sourceaddr; - isc_sockaddr_t masteraddr; - isc_time_t now; - const char *soa_before = ""; - - UNUSED(task); - - INSIST(task == zone->task); - - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { - result = ISC_R_CANCELED; - goto cleanup; - } - - TIME_NOW(&now); - - isc_sockaddr_format(&zone->masteraddr, master, sizeof(master)); - if (dns_zonemgr_unreachable(zone->zmgr, &zone->masteraddr, - &zone->sourceaddr, &now)) { - isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source)); - dns_zone_log(zone, ISC_LOG_INFO, - "got_transfer_quota: skipping zone transfer as " - "master %s (source %s) is unreachable (cached)", - master, source); - result = ISC_R_CANCELED; - goto cleanup; - } - - isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); - (void)dns_peerlist_peerbyaddr(zone->view->peers, &masterip, &peer); + isc_uint32_t nxfrsin, nxfrsperns; + dns_zone_t *x; + isc_uint32_t maxtransfersin, maxtransfersperns; + isc_event_t *e; - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) - soa_before = "SOA before "; /* - * Decide whether we should request IXFR or AXFR. + * Find any configured information about the server we'd + * like to transfer this zone from. */ - if (zone->db == NULL) { - dns_zone_log(zone, ISC_LOG_DEBUG(1), - "no database exists yet, requesting AXFR of " - "initial version from %s", master); - xfrtype = dns_rdatatype_axfr; - } else if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS)) { - dns_zone_log(zone, ISC_LOG_DEBUG(1), "ixfr-from-differences " - "set, requesting %sAXFR from %s", soa_before, - master); - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) - xfrtype = dns_rdatatype_soa; - else - xfrtype = dns_rdatatype_axfr; - } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) { - dns_zone_log(zone, ISC_LOG_DEBUG(1), - "forced reload, requesting AXFR of " - "initial version from %s", master); - xfrtype = dns_rdatatype_axfr; - } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLAG_NOIXFR)) { - dns_zone_log(zone, ISC_LOG_DEBUG(1), - "retrying with AXFR from %s due to " - "previous IXFR failure", master); - xfrtype = dns_rdatatype_axfr; - LOCK_ZONE(zone); - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLAG_NOIXFR); - UNLOCK_ZONE(zone); - } else { - isc_boolean_t use_ixfr = ISC_TRUE; - if (peer != NULL && - dns_peer_getrequestixfr(peer, &use_ixfr) == - ISC_R_SUCCESS) { - ; /* Using peer setting */ - } else { - use_ixfr = zone->view->requestixfr; - } - if (use_ixfr == ISC_FALSE) { - dns_zone_log(zone, ISC_LOG_DEBUG(1), - "IXFR disabled, requesting %sAXFR from %s", - soa_before, master); - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) - xfrtype = dns_rdatatype_soa; - else - xfrtype = dns_rdatatype_axfr; - } else { - dns_zone_log(zone, ISC_LOG_DEBUG(1), - "requesting IXFR from %s", master); - xfrtype = dns_rdatatype_ixfr; - } - } + isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); + (void)dns_peerlist_peerbyaddr(zone->view->peers, + &masterip, &peer); /* - * Determine if we should attempt to sign the request with TSIG. + * Determine the total maximum number of simultaneous + * transfers allowed, and the maximum for this specific + * master. */ - result = ISC_R_NOTFOUND; + maxtransfersin = zmgr->transfersin; + maxtransfersperns = zmgr->transfersperns; + if (peer != NULL) + (void)dns_peer_gettransfers(peer, &maxtransfersperns); + /* - * First, look for a tsig key in the master statement, then - * try for a server key. + * Count the total number of transfers that are in progress, + * and the number of transfers in progress from this master. + * We linearly scan a list of all transfers; if this turns + * out to be too slow, we could hash on the master address. */ - if ((zone->masterkeynames != NULL) && - (zone->masterkeynames[zone->curmaster] != NULL)) { - dns_view_t *view = dns_zone_getview(zone); - dns_name_t *keyname = zone->masterkeynames[zone->curmaster]; - result = dns_view_gettsig(view, keyname, &zone->tsigkey); + nxfrsin = nxfrsperns = 0; + for (x = ISC_LIST_HEAD(zmgr->xfrin_in_progress); + x != NULL; + x = ISC_LIST_NEXT(x, statelink)) + { + isc_netaddr_t xip; + isc_netaddr_fromsockaddr(&xip, &x->masteraddr); + nxfrsin++; + if (isc_netaddr_equal(&xip, &masterip)) + nxfrsperns++; } - if (zone->tsigkey == NULL) - result = dns_view_getpeertsig(zone->view, &masterip, - &zone->tsigkey); - if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { - dns_zone_log(zone, ISC_LOG_ERROR, - "could not get TSIG key for zone transfer: %s", - isc_result_totext(result)); - } + /* Enforce quota. */ + if (nxfrsin >= maxtransfersin) + return (ISC_R_QUOTA); + + if (nxfrsperns >= maxtransfersperns) + return (ISC_R_QUOTA); - LOCK_ZONE(zone); - masteraddr = zone->masteraddr; - sourceaddr = zone->sourceaddr; - UNLOCK_ZONE(zone); - INSIST(isc_sockaddr_pf(&masteraddr) == isc_sockaddr_pf(&sourceaddr)); - result = dns_xfrin_create2(zone, xfrtype, &masteraddr, &sourceaddr, - zone->tsigkey, zone->mctx, - zone->zmgr->timermgr, zone->zmgr->socketmgr, - zone->task, zone_xfrdone, &zone->xfr); - if (result == ISC_R_SUCCESS) { - LOCK_ZONE(zone); - if (xfrtype == dns_rdatatype_axfr) { - if (isc_sockaddr_pf(&masteraddr) == PF_INET) - inc_stats(zone, dns_zonestatscounter_axfrreqv4); - else - inc_stats(zone, dns_zonestatscounter_axfrreqv6); - } else if (xfrtype == dns_rdatatype_ixfr) { - if (isc_sockaddr_pf(&masteraddr) == PF_INET) - inc_stats(zone, dns_zonestatscounter_ixfrreqv4); - else - inc_stats(zone, dns_zonestatscounter_ixfrreqv6); - } - UNLOCK_ZONE(zone); - } - cleanup: /* - * Any failure in this function is handled like a failed - * zone transfer. This ensures that we get removed from - * zmgr->xfrin_in_progress. + * We have sufficient quota. Move the zone to the "xfrin_in_progress" + * list and send it an event to let it start the actual transfer in the + * context of its own task. */ - if (result != ISC_R_SUCCESS) - zone_xfrdone(zone, result); + e = isc_event_allocate(zmgr->mctx, zmgr, + DNS_EVENT_ZONESTARTXFRIN, + got_transfer_quota, zone, + sizeof(isc_event_t)); + if (e == NULL) + return (ISC_R_NOMEMORY); - isc_event_free(&event); + LOCK_ZONE(zone); + INSIST(zone->statelist == &zmgr->waiting_for_xfrin); + ISC_LIST_UNLINK(zmgr->waiting_for_xfrin, zone, statelink); + ISC_LIST_APPEND(zmgr->xfrin_in_progress, zone, statelink); + zone->statelist = &zmgr->xfrin_in_progress; + isc_task_send(zone->task, &e); + dns_zone_log(zone, ISC_LOG_INFO, "Transfer started."); + UNLOCK_ZONE(zone); + + return (ISC_R_SUCCESS); } -/* - * Update forwarding support. - */ +void +dns_zonemgr_setiolimit(dns_zonemgr_t *zmgr, isc_uint32_t iolimit) { -static void -forward_destroy(dns_forward_t *forward) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + REQUIRE(iolimit > 0); - forward->magic = 0; - if (forward->request != NULL) - dns_request_destroy(&forward->request); - if (forward->msgbuf != NULL) - isc_buffer_free(&forward->msgbuf); - if (forward->zone != NULL) - dns_zone_idetach(&forward->zone); - isc_mem_putanddetach(&forward->mctx, forward, sizeof(*forward)); + zmgr->iolimit = iolimit; +} + +isc_uint32_t +dns_zonemgr_getiolimit(dns_zonemgr_t *zmgr) { + + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + return (zmgr->iolimit); } +/* + * Get permission to request a file handle from the OS. + * An event will be sent to action when one is available. + * There are two queues available (high and low), the high + * queue will be serviced before the low one. + * + * zonemgr_putio() must be called after the event is delivered to + * 'action'. + */ + static isc_result_t -sendtomaster(dns_forward_t *forward) { - isc_result_t result; - isc_sockaddr_t src; +zonemgr_getio(dns_zonemgr_t *zmgr, isc_boolean_t high, + isc_task_t *task, isc_taskaction_t action, void *arg, + dns_io_t **iop) +{ + dns_io_t *io; + isc_boolean_t queue; - LOCK_ZONE(forward->zone); - if (forward->which >= forward->zone->masterscnt) { - UNLOCK_ZONE(forward->zone); - return (ISC_R_NOMORE); + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + REQUIRE(iop != NULL && *iop == NULL); + + io = isc_mem_get(zmgr->mctx, sizeof(*io)); + if (io == NULL) + return (ISC_R_NOMEMORY); + io->event = isc_event_allocate(zmgr->mctx, task, DNS_EVENT_IOREADY, + action, arg, sizeof(*io->event)); + if (io->event == NULL) { + isc_mem_put(zmgr->mctx, io, sizeof(*io)); + return (ISC_R_NOMEMORY); } + io->zmgr = zmgr; + io->high = high; + io->task = NULL; + isc_task_attach(task, &io->task); + ISC_LINK_INIT(io, link); + io->magic = IO_MAGIC; - forward->addr = forward->zone->masters[forward->which]; - /* - * Always use TCP regardless of whether the original update - * used TCP. - * XXX The timeout may but a bit small if we are far down a - * transfer graph and the master has to try several masters. - */ - switch (isc_sockaddr_pf(&forward->addr)) { - case PF_INET: - src = forward->zone->xfrsource4; - break; - case PF_INET6: - src = forward->zone->xfrsource6; - break; - default: - result = ISC_R_NOTIMPLEMENTED; - goto unlock; + LOCK(&zmgr->iolock); + zmgr->ioactive++; + queue = ISC_TF(zmgr->ioactive > zmgr->iolimit); + if (queue) { + if (io->high) + ISC_LIST_APPEND(zmgr->high, io, link); + else + ISC_LIST_APPEND(zmgr->low, io, link); } - result = dns_request_createraw(forward->zone->view->requestmgr, - forward->msgbuf, - &src, &forward->addr, - DNS_REQUESTOPT_TCP, 15 /* XXX */, - forward->zone->task, - forward_callback, forward, - &forward->request); - unlock: - UNLOCK_ZONE(forward->zone); - return (result); + UNLOCK(&zmgr->iolock); + *iop = io; + + if (!queue) { + isc_task_send(io->task, &io->event); + } + return (ISC_R_SUCCESS); } static void -forward_callback(isc_task_t *task, isc_event_t *event) { - const char me[] = "forward_callback"; - dns_requestevent_t *revent = (dns_requestevent_t *)event; - dns_message_t *msg = NULL; - char master[ISC_SOCKADDR_FORMATSIZE]; - isc_result_t result; - dns_forward_t *forward; - dns_zone_t *zone; +zonemgr_putio(dns_io_t **iop) { + dns_io_t *io; + dns_io_t *next; + dns_zonemgr_t *zmgr; - UNUSED(task); + REQUIRE(iop != NULL); + io = *iop; + REQUIRE(DNS_IO_VALID(io)); - forward = revent->ev_arg; - INSIST(DNS_FORWARD_VALID(forward)); - zone = forward->zone; - INSIST(DNS_ZONE_VALID(zone)); + *iop = NULL; - ENTER; + INSIST(!ISC_LINK_LINKED(io, link)); + INSIST(io->event == NULL); - isc_sockaddr_format(&forward->addr, master, sizeof(master)); + zmgr = io->zmgr; + isc_task_detach(&io->task); + io->magic = 0; + isc_mem_put(zmgr->mctx, io, sizeof(*io)); - if (revent->result != ISC_R_SUCCESS) { - dns_zone_log(zone, ISC_LOG_INFO, - "could not forward dynamic update to %s: %s", - master, dns_result_totext(revent->result)); - goto next_master; + LOCK(&zmgr->iolock); + INSIST(zmgr->ioactive > 0); + zmgr->ioactive--; + next = HEAD(zmgr->high); + if (next == NULL) + next = HEAD(zmgr->low); + if (next != NULL) { + if (next->high) + ISC_LIST_UNLINK(zmgr->high, next, link); + else + ISC_LIST_UNLINK(zmgr->low, next, link); + INSIST(next->event != NULL); } + UNLOCK(&zmgr->iolock); + if (next != NULL) + isc_task_send(next->task, &next->event); +} - result = dns_message_create(zone->mctx, DNS_MESSAGE_INTENTPARSE, &msg); - if (result != ISC_R_SUCCESS) - goto next_master; +static void +zonemgr_cancelio(dns_io_t *io) { + isc_boolean_t send_event = ISC_FALSE; - result = dns_request_getresponse(revent->request, msg, - DNS_MESSAGEPARSE_PRESERVEORDER | - DNS_MESSAGEPARSE_CLONEBUFFER); - if (result != ISC_R_SUCCESS) - goto next_master; + REQUIRE(DNS_IO_VALID(io)); - switch (msg->rcode) { /* - * Pass these rcodes back to client. + * If we are queued to be run then dequeue. */ - case dns_rcode_noerror: - case dns_rcode_yxdomain: - case dns_rcode_yxrrset: - case dns_rcode_nxrrset: - case dns_rcode_refused: - case dns_rcode_nxdomain: - break; - - /* These should not occur if the masters/zone are valid. */ - case dns_rcode_notzone: - case dns_rcode_notauth: { - char rcode[128]; - isc_buffer_t rb; - - isc_buffer_init(&rb, rcode, sizeof(rcode)); - (void)dns_rcode_totext(msg->rcode, &rb); - dns_zone_log(zone, ISC_LOG_WARNING, - "forwarding dynamic update: " - "unexpected response: master %s returned: %.*s", - master, (int)rb.used, rcode); - goto next_master; - } + LOCK(&io->zmgr->iolock); + if (ISC_LINK_LINKED(io, link)) { + if (io->high) + ISC_LIST_UNLINK(io->zmgr->high, io, link); + else + ISC_LIST_UNLINK(io->zmgr->low, io, link); - /* Try another server for these rcodes. */ - case dns_rcode_formerr: - case dns_rcode_servfail: - case dns_rcode_notimp: - case dns_rcode_badvers: - default: - goto next_master; + send_event = ISC_TRUE; + INSIST(io->event != NULL); } - - /* call callback */ - (forward->callback)(forward->callback_arg, ISC_R_SUCCESS, msg); - msg = NULL; - dns_request_destroy(&forward->request); - forward_destroy(forward); - isc_event_free(&event); - return; - - next_master: - if (msg != NULL) - dns_message_destroy(&msg); - isc_event_free(&event); - forward->which++; - dns_request_destroy(&forward->request); - result = sendtomaster(forward); - if (result != ISC_R_SUCCESS) { - /* call callback */ - dns_zone_log(zone, ISC_LOG_DEBUG(3), - "exhausted dynamic update forwarder list"); - (forward->callback)(forward->callback_arg, result, NULL); - forward_destroy(forward); + UNLOCK(&io->zmgr->iolock); + if (send_event) { + io->event->ev_attributes |= ISC_EVENTATTR_CANCELED; + isc_task_send(io->task, &io->event); } } -isc_result_t -dns_zone_forwardupdate(dns_zone_t *zone, dns_message_t *msg, - dns_updatecallback_t callback, void *callback_arg) -{ - dns_forward_t *forward; +static void +zone_saveunique(dns_zone_t *zone, const char *path, const char *templat) { + char *buf; + int buflen; isc_result_t result; - isc_region_t *mr; - - REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(msg != NULL); - REQUIRE(callback != NULL); - forward = isc_mem_get(zone->mctx, sizeof(*forward)); - if (forward == NULL) - return (ISC_R_NOMEMORY); - - forward->request = NULL; - forward->zone = NULL; - forward->msgbuf = NULL; - forward->which = 0; - forward->mctx = 0; - forward->callback = callback; - forward->callback_arg = callback_arg; - forward->magic = FORWARD_MAGIC; + buflen = strlen(path) + strlen(templat) + 2; - mr = dns_message_getrawmessage(msg); - if (mr == NULL) { - result = ISC_R_UNEXPECTEDEND; - goto cleanup; - } + buf = isc_mem_get(zone->mctx, buflen); + if (buf == NULL) + return; - result = isc_buffer_allocate(zone->mctx, &forward->msgbuf, mr->length); + result = isc_file_template(path, templat, buf, buflen); if (result != ISC_R_SUCCESS) goto cleanup; - result = isc_buffer_copyregion(forward->msgbuf, mr); + + result = isc_file_renameunique(path, buf); if (result != ISC_R_SUCCESS) goto cleanup; - isc_mem_attach(zone->mctx, &forward->mctx); - dns_zone_iattach(zone, &forward->zone); - result = sendtomaster(forward); + dns_zone_log(zone, ISC_LOG_WARNING, "saved '%s' as '%s'", + path, buf); cleanup: - if (result != ISC_R_SUCCESS) { - forward_destroy(forward); - } - return (result); + isc_mem_put(zone->mctx, buf, buflen); } -isc_result_t -dns_zone_next(dns_zone_t *zone, dns_zone_t **next) { - REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(next != NULL && *next == NULL); +#if 0 +/* Hook for ondestroy notification from a database. */ - *next = ISC_LIST_NEXT(zone, link); - if (*next == NULL) - return (ISC_R_NOMORE); - else - return (ISC_R_SUCCESS); -} +static void +dns_zonemgr_dbdestroyed(isc_task_t *task, isc_event_t *event) { + dns_db_t *db = event->sender; + UNUSED(task); -isc_result_t -dns_zone_first(dns_zonemgr_t *zmgr, dns_zone_t **first) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - REQUIRE(first != NULL && *first == NULL); + isc_event_free(&event); - *first = ISC_LIST_HEAD(zmgr->zones); - if (*first == NULL) - return (ISC_R_NOMORE); - else - return (ISC_R_SUCCESS); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), + "database (%p) destroyed", (void*) db); } +#endif -/*** - *** Zone manager. - ***/ - -isc_result_t -dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, - isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, - dns_zonemgr_t **zmgrp) -{ - dns_zonemgr_t *zmgr; - isc_result_t result; +void +dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value) { isc_interval_t interval; + isc_uint32_t s, ns; + isc_uint32_t pertic; + isc_result_t result; - zmgr = isc_mem_get(mctx, sizeof(*zmgr)); - if (zmgr == NULL) - return (ISC_R_NOMEMORY); - zmgr->mctx = NULL; - zmgr->refs = 1; - isc_mem_attach(mctx, &zmgr->mctx); - zmgr->taskmgr = taskmgr; - zmgr->timermgr = timermgr; - zmgr->socketmgr = socketmgr; - zmgr->zonetasks = NULL; - zmgr->task = NULL; - zmgr->rl = NULL; - ISC_LIST_INIT(zmgr->zones); - ISC_LIST_INIT(zmgr->waiting_for_xfrin); - ISC_LIST_INIT(zmgr->xfrin_in_progress); - memset(zmgr->unreachable, 0, sizeof(zmgr->unreachable)); - result = isc_rwlock_init(&zmgr->rwlock, 0, 0); - if (result != ISC_R_SUCCESS) - goto free_mem; + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - zmgr->transfersin = 10; - zmgr->transfersperns = 2; + if (value == 0) + value = 1; - /* Create the zone task pool. */ - result = isc_taskpool_create(taskmgr, mctx, - 8 /* XXX */, 2, &zmgr->zonetasks); - if (result != ISC_R_SUCCESS) - goto free_rwlock; + if (value == 1) { + s = 1; + ns = 0; + pertic = 1; + } else if (value <= 10) { + s = 0; + ns = 1000000000 / value; + pertic = 1; + } else { + s = 0; + ns = (1000000000 / value) * 10; + pertic = 10; + } - /* Create a single task for queueing of SOA queries. */ - result = isc_task_create(taskmgr, 1, &zmgr->task); - if (result != ISC_R_SUCCESS) - goto free_taskpool; - isc_task_setname(zmgr->task, "zmgr", zmgr); - result = isc_ratelimiter_create(mctx, timermgr, zmgr->task, - &zmgr->rl); - if (result != ISC_R_SUCCESS) - goto free_task; - /* default to 20 refresh queries / notifies per second. */ - isc_interval_set(&interval, 0, 1000000000/2); + isc_interval_set(&interval, s, ns); result = isc_ratelimiter_setinterval(zmgr->rl, &interval); RUNTIME_CHECK(result == ISC_R_SUCCESS); - isc_ratelimiter_setpertic(zmgr->rl, 10); + isc_ratelimiter_setpertic(zmgr->rl, pertic); - zmgr->iolimit = 1; - zmgr->ioactive = 0; - ISC_LIST_INIT(zmgr->high); - ISC_LIST_INIT(zmgr->low); + zmgr->serialqueryrate = value; +} - result = isc_mutex_init(&zmgr->iolock); - if (result != ISC_R_SUCCESS) - goto free_rl; +unsigned int +dns_zonemgr_getserialqueryrate(dns_zonemgr_t *zmgr) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + return (zmgr->serialqueryrate); +} + +static isc_boolean_t +dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, + isc_sockaddr_t *local, isc_time_t *now) +{ + unsigned int i; + isc_rwlocktype_t locktype; + isc_result_t result; + isc_uint32_t seconds = isc_time_seconds(now); + + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + locktype = isc_rwlocktype_read; + RWLOCK(&zmgr->rwlock, locktype); + for (i = 0; i < UNREACH_CHACHE_SIZE; i++) { + if (zmgr->unreachable[i].expire >= seconds && + isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && + isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) { + result = isc_rwlock_tryupgrade(&zmgr->rwlock); + if (result == ISC_R_SUCCESS) { + locktype = isc_rwlocktype_write; + zmgr->unreachable[i].last = seconds; + } + break; + } + } + RWUNLOCK(&zmgr->rwlock, locktype); + return (ISC_TF(i < UNREACH_CHACHE_SIZE)); +} - zmgr->magic = ZONEMGR_MAGIC; +void +dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, + isc_sockaddr_t *local, isc_time_t *now) +{ + isc_uint32_t seconds = isc_time_seconds(now); + isc_uint32_t last = seconds; + unsigned int i, slot = UNREACH_CHACHE_SIZE, oldest = 0; - *zmgrp = zmgr; - return (ISC_R_SUCCESS); + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); -#if 0 - free_iolock: - DESTROYLOCK(&zmgr->iolock); -#endif - free_rl: - isc_ratelimiter_detach(&zmgr->rl); - free_task: - isc_task_detach(&zmgr->task); - free_taskpool: - isc_taskpool_destroy(&zmgr->zonetasks); - free_rwlock: - isc_rwlock_destroy(&zmgr->rwlock); - free_mem: - isc_mem_put(zmgr->mctx, zmgr, sizeof(*zmgr)); - isc_mem_detach(&mctx); - return (result); + RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); + for (i = 0; i < UNREACH_CHACHE_SIZE; i++) { + /* Existing entry? */ + if (isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && + isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) + break; + /* Empty slot? */ + if (zmgr->unreachable[i].expire < seconds) + slot = i; + /* Least recently used slot? */ + if (zmgr->unreachable[i].last < last) { + last = zmgr->unreachable[i].last; + oldest = i; + } + } + if (i < UNREACH_CHACHE_SIZE) { + /* + * Found a existing entry. Update the expire timer and + * last usage timestamps. + */ + zmgr->unreachable[i].expire = seconds + UNREACH_HOLD_TIME; + zmgr->unreachable[i].last = seconds; + } else if (slot != UNREACH_CHACHE_SIZE) { + /* + * Found a empty slot. Add a new entry to the cache. + */ + zmgr->unreachable[slot].expire = seconds + UNREACH_HOLD_TIME; + zmgr->unreachable[slot].last = seconds; + zmgr->unreachable[slot].remote = *remote; + zmgr->unreachable[slot].local = *local; + } else { + /* + * Replace the least recently used entry in the cache. + */ + zmgr->unreachable[oldest].expire = seconds + UNREACH_HOLD_TIME; + zmgr->unreachable[oldest].last = seconds; + zmgr->unreachable[oldest].remote = *remote; + zmgr->unreachable[oldest].local = *local; + } + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); } -isc_result_t -dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) { - isc_result_t result; - +void +dns_zone_forcereload(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); + if (zone->type == dns_zone_master) + return; + LOCK_ZONE(zone); - REQUIRE(zone->task == NULL); - REQUIRE(zone->timer == NULL); - REQUIRE(zone->zmgr == NULL); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_FORCEXFER); + UNLOCK_ZONE(zone); + dns_zone_refresh(zone); +} - isc_taskpool_gettask(zmgr->zonetasks, - dns_name_hash(dns_zone_getorigin(zone), - ISC_FALSE), - &zone->task); +isc_boolean_t +dns_zone_isforced(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + + return (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)); +} +isc_result_t +dns_zone_setstatistics(dns_zone_t *zone, isc_boolean_t on) { /* - * Set the task name. The tag will arbitrarily point to one - * of the zones sharing the task (in practice, the one - * to be managed last). + * This function is obsoleted. */ - isc_task_setname(zone->task, "zone", zone); - - result = isc_timer_create(zmgr->timermgr, isc_timertype_inactive, - NULL, NULL, - zone->task, zone_timer, zone, - &zone->timer); - - if (result != ISC_R_SUCCESS) - goto cleanup_task; + UNUSED(zone); + UNUSED(on); + return (ISC_R_NOTIMPLEMENTED); +} +isc_uint64_t * +dns_zone_getstatscounters(dns_zone_t *zone) { /* - * The timer "holds" a iref. + * This function is obsoleted. */ - zone->irefs++; - INSIST(zone->irefs != 0); - - ISC_LIST_APPEND(zmgr->zones, zone, link); - zone->zmgr = zmgr; - zmgr->refs++; - - goto unlock; + UNUSED(zone); + return (NULL); +} - cleanup_task: - isc_task_detach(&zone->task); +void +dns_zone_setstats(dns_zone_t *zone, isc_stats_t *stats) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(zone->stats == NULL); - unlock: + LOCK_ZONE(zone); + zone->stats = NULL; + isc_stats_attach(stats, &zone->stats); UNLOCK_ZONE(zone); - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); - return (result); } void -dns_zonemgr_releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) { - isc_boolean_t free_now = ISC_FALSE; - +dns_zone_setrequeststats(dns_zone_t *zone, isc_stats_t *stats) { REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - REQUIRE(zone->zmgr == zmgr); - RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); LOCK_ZONE(zone); - - ISC_LIST_UNLINK(zmgr->zones, zone, link); - zone->zmgr = NULL; - zmgr->refs--; - if (zmgr->refs == 0) - free_now = ISC_TRUE; - + if (zone->requeststats_on && stats == NULL) + zone->requeststats_on = ISC_FALSE; + else if (!zone->requeststats_on && stats != NULL) { + if (zone->requeststats == NULL) { + isc_stats_attach(stats, &zone->requeststats); + zone->requeststats_on = ISC_TRUE; + } + } UNLOCK_ZONE(zone); - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); - if (free_now) - zonemgr_free(zmgr); - ENSURE(zone->zmgr == NULL); + return; } -void -dns_zonemgr_attach(dns_zonemgr_t *source, dns_zonemgr_t **target) { - REQUIRE(DNS_ZONEMGR_VALID(source)); - REQUIRE(target != NULL && *target == NULL); - - RWLOCK(&source->rwlock, isc_rwlocktype_write); - REQUIRE(source->refs > 0); - source->refs++; - INSIST(source->refs > 0); - RWUNLOCK(&source->rwlock, isc_rwlocktype_write); - *target = source; +isc_stats_t * +dns_zone_getrequeststats(dns_zone_t *zone) { + /* + * We don't lock zone for efficiency reason. This is not catastrophic + * because requeststats must always be valid when requeststats_on is + * true. + * Some counters may be incremented while requeststats_on is becoming + * false, or some cannot be incremented just after the statistics are + * installed, but it shouldn't matter much in practice. + */ + if (zone->requeststats_on) + return (zone->requeststats); + else + return (NULL); } void -dns_zonemgr_detach(dns_zonemgr_t **zmgrp) { - dns_zonemgr_t *zmgr; - isc_boolean_t free_now = ISC_FALSE; +dns_zone_dialup(dns_zone_t *zone) { - REQUIRE(zmgrp != NULL); - zmgr = *zmgrp; - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + REQUIRE(DNS_ZONE_VALID(zone)); - RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); - zmgr->refs--; - if (zmgr->refs == 0) - free_now = ISC_TRUE; - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); + zone_debuglog(zone, "dns_zone_dialup", 3, + "notify = %d, refresh = %d", + DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY), + DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)); - if (free_now) - zonemgr_free(zmgr); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY)) + dns_zone_notify(zone); + if (zone->type != dns_zone_master && + DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)) + dns_zone_refresh(zone); +} + +void +dns_zone_setdialup(dns_zone_t *zone, dns_dialuptype_t dialup) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_DIALNOTIFY | + DNS_ZONEFLG_DIALREFRESH | + DNS_ZONEFLG_NOREFRESH); + switch (dialup) { + case dns_dialuptype_no: + break; + case dns_dialuptype_yes: + DNS_ZONE_SETFLAG(zone, (DNS_ZONEFLG_DIALNOTIFY | + DNS_ZONEFLG_DIALREFRESH | + DNS_ZONEFLG_NOREFRESH)); + break; + case dns_dialuptype_notify: + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DIALNOTIFY); + break; + case dns_dialuptype_notifypassive: + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DIALNOTIFY); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOREFRESH); + break; + case dns_dialuptype_refresh: + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DIALREFRESH); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOREFRESH); + break; + case dns_dialuptype_passive: + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOREFRESH); + break; + default: + INSIST(0); + } + UNLOCK_ZONE(zone); } isc_result_t -dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr) { - dns_zone_t *p; +dns_zone_setkeydirectory(dns_zone_t *zone, const char *directory) { + isc_result_t result = ISC_R_SUCCESS; - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + REQUIRE(DNS_ZONE_VALID(zone)); - RWLOCK(&zmgr->rwlock, isc_rwlocktype_read); - for (p = ISC_LIST_HEAD(zmgr->zones); - p != NULL; - p = ISC_LIST_NEXT(p, link)) - { - dns_zone_maintenance(p); - } - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); + LOCK_ZONE(zone); + result = dns_zone_setstring(zone, &zone->keydirectory, directory); + UNLOCK_ZONE(zone); - /* - * Recent configuration changes may have increased the - * amount of available transfers quota. Make sure any - * transfers currently blocked on quota get started if - * possible. - */ - RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); - zmgr_resume_xfrs(zmgr, ISC_TRUE); - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); - return (ISC_R_SUCCESS); + return (result); } -void -dns_zonemgr_resumexfrs(dns_zonemgr_t *zmgr) { - - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); +const char * +dns_zone_getkeydirectory(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); - RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); - zmgr_resume_xfrs(zmgr, ISC_TRUE); - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); + return (zone->keydirectory); } -void -dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) { +unsigned int +dns_zonemgr_getcount(dns_zonemgr_t *zmgr, int state) { + dns_zone_t *zone; + unsigned int count = 0; + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - isc_ratelimiter_shutdown(zmgr->rl); + RWLOCK(&zmgr->rwlock, isc_rwlocktype_read); + switch (state) { + case DNS_ZONESTATE_XFERRUNNING: + for (zone = ISC_LIST_HEAD(zmgr->xfrin_in_progress); + zone != NULL; + zone = ISC_LIST_NEXT(zone, statelink)) + count++; + break; + case DNS_ZONESTATE_XFERDEFERRED: + for (zone = ISC_LIST_HEAD(zmgr->waiting_for_xfrin); + zone != NULL; + zone = ISC_LIST_NEXT(zone, statelink)) + count++; + break; + case DNS_ZONESTATE_SOAQUERY: + for (zone = ISC_LIST_HEAD(zmgr->zones); + zone != NULL; + zone = ISC_LIST_NEXT(zone, link)) + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH)) + count++; + break; + case DNS_ZONESTATE_ANY: + for (zone = ISC_LIST_HEAD(zmgr->zones); + zone != NULL; + zone = ISC_LIST_NEXT(zone, link)) { + dns_view_t *view = zone->view; + if (view != NULL && strcmp(view->name, "_bind") == 0) + continue; + count++; + } + break; + default: + INSIST(0); + } - if (zmgr->task != NULL) - isc_task_destroy(&zmgr->task); - if (zmgr->zonetasks != NULL) - isc_taskpool_destroy(&zmgr->zonetasks); + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); + + return (count); } -static void -zonemgr_free(dns_zonemgr_t *zmgr) { - isc_mem_t *mctx; +isc_result_t +dns_zone_checknames(dns_zone_t *zone, dns_name_t *name, dns_rdata_t *rdata) { + isc_boolean_t ok = ISC_TRUE; + isc_boolean_t fail = ISC_FALSE; + char namebuf[DNS_NAME_FORMATSIZE]; + char namebuf2[DNS_NAME_FORMATSIZE]; + char typebuf[DNS_RDATATYPE_FORMATSIZE]; + int level = ISC_LOG_WARNING; + dns_name_t bad; - INSIST(zmgr->refs == 0); - INSIST(ISC_LIST_EMPTY(zmgr->zones)); + REQUIRE(DNS_ZONE_VALID(zone)); - zmgr->magic = 0; + if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES)) + return (ISC_R_SUCCESS); - DESTROYLOCK(&zmgr->iolock); - isc_ratelimiter_detach(&zmgr->rl); + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL)) { + level = ISC_LOG_ERROR; + fail = ISC_TRUE; + } - isc_rwlock_destroy(&zmgr->rwlock); - mctx = zmgr->mctx; - isc_mem_put(zmgr->mctx, zmgr, sizeof(*zmgr)); - isc_mem_detach(&mctx); + ok = dns_rdata_checkowner(name, rdata->rdclass, rdata->type, ISC_TRUE); + if (!ok) { + dns_name_format(name, namebuf, sizeof(namebuf)); + dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf)); + dns_zone_log(zone, level, "%s/%s: %s", namebuf, typebuf, + dns_result_totext(DNS_R_BADOWNERNAME)); + if (fail) + return (DNS_R_BADOWNERNAME); + } + + dns_name_init(&bad, NULL); + ok = dns_rdata_checknames(rdata, name, &bad); + if (!ok) { + dns_name_format(name, namebuf, sizeof(namebuf)); + dns_name_format(&bad, namebuf2, sizeof(namebuf2)); + dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf)); + dns_zone_log(zone, level, "%s/%s: %s: %s ", namebuf, typebuf, + namebuf2, dns_result_totext(DNS_R_BADNAME)); + if (fail) + return (DNS_R_BADNAME); + } + + return (ISC_R_SUCCESS); } void -dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, isc_uint32_t value) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - zmgr->transfersin = value; +dns_zone_setcheckmx(dns_zone_t *zone, dns_checkmxfunc_t checkmx) { + REQUIRE(DNS_ZONE_VALID(zone)); + zone->checkmx = checkmx; } -isc_uint32_t -dns_zonemgr_getttransfersin(dns_zonemgr_t *zmgr) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); +void +dns_zone_setchecksrv(dns_zone_t *zone, dns_checksrvfunc_t checksrv) { + REQUIRE(DNS_ZONE_VALID(zone)); + zone->checksrv = checksrv; +} - return (zmgr->transfersin); +void +dns_zone_setcheckns(dns_zone_t *zone, dns_checknsfunc_t checkns) { + REQUIRE(DNS_ZONE_VALID(zone)); + zone->checkns = checkns; } void -dns_zonemgr_settransfersperns(dns_zonemgr_t *zmgr, isc_uint32_t value) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); +dns_zone_setisself(dns_zone_t *zone, dns_isselffunc_t isself, void *arg) { + REQUIRE(DNS_ZONE_VALID(zone)); - zmgr->transfersperns = value; + LOCK_ZONE(zone); + zone->isself = isself; + zone->isselfarg = arg; + UNLOCK_ZONE(zone); } -isc_uint32_t -dns_zonemgr_getttransfersperns(dns_zonemgr_t *zmgr) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); +void +dns_zone_setnotifydelay(dns_zone_t *zone, isc_uint32_t delay) { + REQUIRE(DNS_ZONE_VALID(zone)); - return (zmgr->transfersperns); + LOCK_ZONE(zone); + zone->notifydelay = delay; + UNLOCK_ZONE(zone); } -/* - * Try to start a new incoming zone transfer to fill a quota - * slot that was just vacated. - * - * Requires: - * The zone manager is locked by the caller. - */ -static void -zmgr_resume_xfrs(dns_zonemgr_t *zmgr, isc_boolean_t multi) { - dns_zone_t *zone; - dns_zone_t *next; +isc_uint32_t +dns_zone_getnotifydelay(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); - for (zone = ISC_LIST_HEAD(zmgr->waiting_for_xfrin); - zone != NULL; - zone = next) - { - isc_result_t result; - next = ISC_LIST_NEXT(zone, statelink); - result = zmgr_start_xfrin_ifquota(zmgr, zone); - if (result == ISC_R_SUCCESS) { - if (multi) - continue; - /* - * We successfully filled the slot. We're done. - */ - break; - } else if (result == ISC_R_QUOTA) { - /* - * Not enough quota. This is probably the per-server - * quota, because we usually get called when a unit of - * global quota has just been freed. Try the next - * zone, it may succeed if it uses another master. - */ - continue; - } else { - dns_zone_log(zone, ISC_LOG_DEBUG(1), - "starting zone transfer: %s", - isc_result_totext(result)); - break; - } - } + return (zone->notifydelay); } -/* - * Try to start an incoming zone transfer for 'zone', quota permitting. - * - * Requires: - * The zone manager is locked by the caller. - * - * Returns: - * ISC_R_SUCCESS There was enough quota and we attempted to - * start a transfer. zone_xfrdone() has been or will - * be called. - * ISC_R_QUOTA Not enough quota. - * Others Failure. - */ -static isc_result_t -zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) { - dns_peer_t *peer = NULL; - isc_netaddr_t masterip; - isc_uint32_t nxfrsin, nxfrsperns; - dns_zone_t *x; - isc_uint32_t maxtransfersin, maxtransfersperns; - isc_event_t *e; - - /* - * Find any configured information about the server we'd - * like to transfer this zone from. - */ - isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); - (void)dns_peerlist_peerbyaddr(zone->view->peers, - &masterip, &peer); +isc_result_t +dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, + isc_uint16_t keyid, isc_boolean_t delete) +{ + isc_result_t result; + REQUIRE(DNS_ZONE_VALID(zone)); - /* - * Determine the total maximum number of simultaneous - * transfers allowed, and the maximum for this specific - * master. - */ - maxtransfersin = zmgr->transfersin; - maxtransfersperns = zmgr->transfersperns; - if (peer != NULL) - (void)dns_peer_gettransfers(peer, &maxtransfersperns); + dns_zone_log(zone, ISC_LOG_NOTICE, + "dns_zone_signwithkey(algorithm=%u, keyid=%u)", + algorithm, keyid); + LOCK_ZONE(zone); + result = zone_signwithkey(zone, algorithm, keyid, delete); + UNLOCK_ZONE(zone); - /* - * Count the total number of transfers that are in progress, - * and the number of transfers in progress from this master. - * We linearly scan a list of all transfers; if this turns - * out to be too slow, we could hash on the master address. - */ - nxfrsin = nxfrsperns = 0; - for (x = ISC_LIST_HEAD(zmgr->xfrin_in_progress); - x != NULL; - x = ISC_LIST_NEXT(x, statelink)) - { - isc_netaddr_t xip; - isc_netaddr_fromsockaddr(&xip, &x->masteraddr); - nxfrsin++; - if (isc_netaddr_equal(&xip, &masterip)) - nxfrsperns++; - } + return (result); +} - /* Enforce quota. */ - if (nxfrsin >= maxtransfersin) - return (ISC_R_QUOTA); +static const char *hex = "0123456789ABCDEF"; - if (nxfrsperns >= maxtransfersperns) - return (ISC_R_QUOTA); +isc_result_t +dns_zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { + isc_result_t result; + char salt[255*2+1]; + unsigned int i, j; - /* - * We have sufficient quota. Move the zone to the "xfrin_in_progress" - * list and send it an event to let it start the actual transfer in the - * context of its own task. - */ - e = isc_event_allocate(zmgr->mctx, zmgr, - DNS_EVENT_ZONESTARTXFRIN, - got_transfer_quota, zone, - sizeof(isc_event_t)); - if (e == NULL) - return (ISC_R_NOMEMORY); + REQUIRE(DNS_ZONE_VALID(zone)); + if (nsec3param->salt_length != 0) { + INSIST((nsec3param->salt_length * 2U) < sizeof(salt)); + for (i = 0, j = 0; i < nsec3param->salt_length; i++) { + salt[j++] = hex[(nsec3param->salt[i] >> 4) & 0xf]; + salt[j++] = hex[nsec3param->salt[i] & 0xf]; + } + salt[j] = '\0'; + } else + strcpy(salt, "-"); + dns_zone_log(zone, ISC_LOG_NOTICE, + "dns_zone_addnsec3chain(hash=%u, iterations=%u, salt=%s)", + nsec3param->hash, nsec3param->iterations, + salt); LOCK_ZONE(zone); - INSIST(zone->statelist == &zmgr->waiting_for_xfrin); - ISC_LIST_UNLINK(zmgr->waiting_for_xfrin, zone, statelink); - ISC_LIST_APPEND(zmgr->xfrin_in_progress, zone, statelink); - zone->statelist = &zmgr->xfrin_in_progress; - isc_task_send(zone->task, &e); - dns_zone_log(zone, ISC_LOG_INFO, "Transfer started."); + result = zone_addnsec3chain(zone, nsec3param); UNLOCK_ZONE(zone); - return (ISC_R_SUCCESS); + return (result); } void -dns_zonemgr_setiolimit(dns_zonemgr_t *zmgr, isc_uint32_t iolimit) { - - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - REQUIRE(iolimit > 0); +dns_zone_setnodes(dns_zone_t *zone, isc_uint32_t nodes) { + REQUIRE(DNS_ZONE_VALID(zone)); - zmgr->iolimit = iolimit; + if (nodes == 0) + nodes = 1; + zone->nodes = nodes; } -isc_uint32_t -dns_zonemgr_getiolimit(dns_zonemgr_t *zmgr) { +void +dns_zone_setsignatures(dns_zone_t *zone, isc_uint32_t signatures) { + REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + /* + * We treat signatures as a signed value so explicitly + * limit its range here. + */ + if (signatures > ISC_INT32_MAX) + signatures = ISC_INT32_MAX; + else if (signatures == 0) + signatures = 1; + zone->signatures = signatures; +} - return (zmgr->iolimit); +void +dns_zone_setprivatetype(dns_zone_t *zone, dns_rdatatype_t type) { + REQUIRE(DNS_ZONE_VALID(zone)); + zone->privatetype = type; } -/* - * Get permission to request a file handle from the OS. - * An event will be sent to action when one is available. - * There are two queues available (high and low), the high - * queue will be serviced before the low one. - * - * zonemgr_putio() must be called after the event is delivered to - * 'action'. - */ +dns_rdatatype_t +dns_zone_getprivatetype(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (zone->privatetype); +} static isc_result_t -zonemgr_getio(dns_zonemgr_t *zmgr, isc_boolean_t high, - isc_task_t *task, isc_taskaction_t action, void *arg, - dns_io_t **iop) +zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid, + isc_boolean_t delete) { - dns_io_t *io; - isc_boolean_t queue; - - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - REQUIRE(iop != NULL && *iop == NULL); + dns_signing_t *signing; + dns_signing_t *current; + isc_result_t result = ISC_R_SUCCESS; + isc_time_t now; - io = isc_mem_get(zmgr->mctx, sizeof(*io)); - if (io == NULL) - return (ISC_R_NOMEMORY); - io->event = isc_event_allocate(zmgr->mctx, task, DNS_EVENT_IOREADY, - action, arg, sizeof(*io->event)); - if (io->event == NULL) { - isc_mem_put(zmgr->mctx, io, sizeof(*io)); + signing = isc_mem_get(zone->mctx, sizeof *signing); + if (signing == NULL) return (ISC_R_NOMEMORY); - } - io->zmgr = zmgr; - io->high = high; - io->task = NULL; - isc_task_attach(task, &io->task); - ISC_LINK_INIT(io, link); - io->magic = IO_MAGIC; - - LOCK(&zmgr->iolock); - zmgr->ioactive++; - queue = ISC_TF(zmgr->ioactive > zmgr->iolimit); - if (queue) { - if (io->high) - ISC_LIST_APPEND(zmgr->high, io, link); - else - ISC_LIST_APPEND(zmgr->low, io, link); - } - UNLOCK(&zmgr->iolock); - *iop = io; - - if (!queue) { - isc_task_send(io->task, &io->event); - } - return (ISC_R_SUCCESS); -} -static void -zonemgr_putio(dns_io_t **iop) { - dns_io_t *io; - dns_io_t *next; - dns_zonemgr_t *zmgr; + signing->magic = 0; + signing->db = NULL; + signing->dbiterator = NULL; + signing->algorithm = algorithm; + signing->keyid = keyid; + signing->delete = delete; + signing->done = ISC_FALSE; - REQUIRE(iop != NULL); - io = *iop; - REQUIRE(DNS_IO_VALID(io)); + TIME_NOW(&now); - *iop = NULL; + for (current = ISC_LIST_HEAD(zone->signing); + current != NULL; + current = ISC_LIST_NEXT(current, link)) { + if (current->db == zone->db && + current->algorithm == signing->algorithm && + current->keyid == signing->keyid) { + if (current->delete != signing->delete) + current->done = ISC_TRUE; + else + goto cleanup; + } + } - INSIST(!ISC_LINK_LINKED(io, link)); - INSIST(io->event == NULL); + if (zone->db != NULL) { + dns_db_attach(zone->db, &signing->db); + result = dns_db_createiterator(signing->db, 0, + &signing->dbiterator); - zmgr = io->zmgr; - isc_task_detach(&io->task); - io->magic = 0; - isc_mem_put(zmgr->mctx, io, sizeof(*io)); + if (result == ISC_R_SUCCESS) + result = dns_dbiterator_first(signing->dbiterator); + if (result == ISC_R_SUCCESS) { + dns_dbiterator_pause(signing->dbiterator); + ISC_LIST_INITANDAPPEND(zone->signing, signing, link); + signing = NULL; + if (isc_time_isepoch(&zone->signingtime)) { + zone->signingtime = now; + if (zone->task != NULL) + zone_settimer(zone, &now); + } + } + } else + result = ISC_R_NOTFOUND; - LOCK(&zmgr->iolock); - INSIST(zmgr->ioactive > 0); - zmgr->ioactive--; - next = HEAD(zmgr->high); - if (next == NULL) - next = HEAD(zmgr->low); - if (next != NULL) { - if (next->high) - ISC_LIST_UNLINK(zmgr->high, next, link); - else - ISC_LIST_UNLINK(zmgr->low, next, link); - INSIST(next->event != NULL); + cleanup: + if (signing != NULL) { + if (signing->db != NULL) + dns_db_detach(&signing->db); + if (signing->dbiterator != NULL) + dns_dbiterator_destroy(&signing->dbiterator); + isc_mem_put(zone->mctx, signing, sizeof *signing); } - UNLOCK(&zmgr->iolock); - if (next != NULL) - isc_task_send(next->task, &next->event); + return (result); } static void -zonemgr_cancelio(dns_io_t *io) { - isc_boolean_t send_event = ISC_FALSE; +logmsg(const char *format, ...) { + va_list args; + va_start(args, format); + isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, + ISC_LOG_DEBUG(1), format, args); + va_end(args); +} + +static void +clear_keylist(dns_dnsseckeylist_t *list, isc_mem_t *mctx) { + dns_dnsseckey_t *key; + while (!ISC_LIST_EMPTY(*list)) { + key = ISC_LIST_HEAD(*list); + ISC_LIST_UNLINK(*list, key, link); + dns_dnsseckey_destroy(mctx, &key); + } +} - REQUIRE(DNS_IO_VALID(io)); +/* Called once; *timep should be set to the current time. */ +static isc_result_t +next_keyevent(dst_key_t *key, isc_stdtime_t *timep) { + isc_result_t result; + isc_stdtime_t now, then = 0, event; + int i; - /* - * If we are queued to be run then dequeue. - */ - LOCK(&io->zmgr->iolock); - if (ISC_LINK_LINKED(io, link)) { - if (io->high) - ISC_LIST_UNLINK(io->zmgr->high, io, link); - else - ISC_LIST_UNLINK(io->zmgr->low, io, link); + now = *timep; - send_event = ISC_TRUE; - INSIST(io->event != NULL); + for (i = 0; i <= DST_MAX_TIMES; i++) { + result = dst_key_gettime(key, i, &event); + if (result == ISC_R_SUCCESS && event > now && + (then == 0 || event < then)) + then = event; } - UNLOCK(&io->zmgr->iolock); - if (send_event) { - io->event->ev_attributes |= ISC_EVENTATTR_CANCELED; - isc_task_send(io->task, &io->event); + + if (then != 0) { + *timep = then; + return (ISC_R_SUCCESS); } + + return (ISC_R_NOTFOUND); } -static void -zone_saveunique(dns_zone_t *zone, const char *path, const char *templat) { - char *buf; - int buflen; +static isc_result_t +rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + const dns_rdata_t *rdata, isc_boolean_t *flag) +{ + dns_rdataset_t rdataset; + dns_dbnode_t *node = NULL; isc_result_t result; - buflen = strlen(path) + strlen(templat) + 2; + dns_rdataset_init(&rdataset); + if (rdata->type == dns_rdatatype_nsec3) + CHECK(dns_db_findnsec3node(db, name, ISC_FALSE, &node)); + else + CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); + result = dns_db_findrdataset(db, node, ver, rdata->type, 0, + (isc_stdtime_t) 0, &rdataset, NULL); + if (result == ISC_R_NOTFOUND) { + *flag = ISC_FALSE; + result = ISC_R_SUCCESS; + goto failure; + } - buf = isc_mem_get(zone->mctx, buflen); - if (buf == NULL) - return; + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t myrdata = DNS_RDATA_INIT; + dns_rdataset_current(&rdataset, &myrdata); + if (!dns_rdata_compare(&myrdata, rdata)) + break; + } + dns_rdataset_disassociate(&rdataset); + if (result == ISC_R_SUCCESS) { + *flag = ISC_TRUE; + } else if (result == ISC_R_NOMORE) { + *flag = ISC_FALSE; + result = ISC_R_SUCCESS; + } - result = isc_file_template(path, templat, buf, buflen); - if (result != ISC_R_SUCCESS) - goto cleanup; + failure: + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); +} - result = isc_file_renameunique(path, buf); - if (result != ISC_R_SUCCESS) - goto cleanup; +/* + * Add records to signal the state of signing or of key removal. + */ +static isc_result_t +add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype, + dns_dbversion_t *ver, dns_diff_t *diff) +{ + dns_difftuple_t *tuple, *newtuple = NULL; + dns_rdata_dnskey_t dnskey; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_boolean_t flag; + isc_region_t r; + isc_result_t result = ISC_R_SUCCESS; + isc_uint16_t keyid; + unsigned char buf[5]; + dns_name_t *name = dns_db_origin(db); - dns_zone_log(zone, ISC_LOG_WARNING, "saved '%s' as '%s'", - path, buf); + for (tuple = ISC_LIST_HEAD(diff->tuples); + tuple != NULL; + tuple = ISC_LIST_NEXT(tuple, link)) { + if (tuple->rdata.type != dns_rdatatype_dnskey) + continue; - cleanup: - isc_mem_put(zone->mctx, buf, buflen); -} + result = dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if ((dnskey.flags & + (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH)) + != DNS_KEYOWNER_ZONE) + continue; -#if 0 -/* Hook for ondestroy notification from a database. */ + dns_rdata_toregion(&tuple->rdata, &r); -static void -dns_zonemgr_dbdestroyed(isc_task_t *task, isc_event_t *event) { - dns_db_t *db = event->sender; - UNUSED(task); + keyid = dst_region_computeid(&r, dnskey.algorithm); - isc_event_free(&event); + buf[0] = dnskey.algorithm; + buf[1] = (keyid & 0xff00) >> 8; + buf[2] = (keyid & 0xff); + buf[3] = (tuple->op == DNS_DIFFOP_ADD) ? 0 : 1; + buf[4] = 0; + rdata.data = buf; + rdata.length = sizeof(buf); + rdata.type = privatetype; + rdata.rdclass = tuple->rdata.rdclass; - isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3), - "database (%p) destroyed", (void*) db); + CHECK(rr_exists(db, ver, name, &rdata, &flag)); + if (flag) + continue; + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, + name, 0, &rdata, &newtuple)); + CHECK(do_one_tuple(&newtuple, db, ver, diff)); + INSIST(newtuple == NULL); + /* + * Remove any record which says this operation has already + * completed. + */ + buf[4] = 1; + CHECK(rr_exists(db, ver, name, &rdata, &flag)); + if (flag) { + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, + name, 0, &rdata, &newtuple)); + CHECK(do_one_tuple(&newtuple, db, ver, diff)); + INSIST(newtuple == NULL); + } + } + failure: + return (result); } -#endif -void -dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value) { - isc_interval_t interval; - isc_uint32_t s, ns; - isc_uint32_t pertic; +static isc_result_t +sign_apex(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, + dns_diff_t *diff, dns_diff_t *sig_diff) +{ isc_result_t result; + isc_stdtime_t now, inception, soaexpire; + isc_boolean_t check_ksk, keyset_kskonly; + dst_key_t *zone_keys[MAXZONEKEYS]; + unsigned int nkeys = 0, i; + dns_difftuple_t *tuple; - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + result = find_zone_keys(zone, db, ver, zone->mctx, MAXZONEKEYS, + zone_keys, &nkeys); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "sign_apex:find_zone_keys -> %s\n", + dns_result_totext(result)); + return (result); + } - if (value == 0) - value = 1; + isc_stdtime_get(&now); + inception = now - 3600; /* Allow for clock skew. */ + soaexpire = now + dns_zone_getsigvalidityinterval(zone); - if (value == 1) { - s = 1; - ns = 0; - pertic = 1; - } else if (value <= 10) { - s = 0; - ns = 1000000000 / value; - pertic = 1; - } else { - s = 0; - ns = (1000000000 / value) * 10; - pertic = 10; + check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); + keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY); + + /* + * See if update_sigs will update DNSKEY signature and if not + * cause them to sign so that so that newly activated keys + * are used. + */ + for (tuple = ISC_LIST_HEAD(diff->tuples); + tuple != NULL; + tuple = ISC_LIST_NEXT(tuple, link)) { + if (tuple->rdata.type == dns_rdatatype_dnskey && + dns_name_equal(&tuple->name, &zone->origin)) + break; } - isc_interval_set(&interval, s, ns); - result = isc_ratelimiter_setinterval(zmgr->rl, &interval); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - isc_ratelimiter_setpertic(zmgr->rl, pertic); + if (tuple == NULL) { + result = del_sigs(zone, db, ver, &zone->origin, + dns_rdatatype_dnskey, sig_diff, + zone_keys, nkeys, now); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "sign_apex:del_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + result = add_sigs(db, ver, &zone->origin, dns_rdatatype_dnskey, + sig_diff, zone_keys, nkeys, zone->mctx, + inception, soaexpire, check_ksk, + keyset_kskonly); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "sign_apex:add_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } + } - zmgr->serialqueryrate = value; -} + result = update_sigs(diff, db, ver, zone_keys, nkeys, zone, + inception, soaexpire, now, check_ksk, + keyset_kskonly, sig_diff); -unsigned int -dns_zonemgr_getserialqueryrate(dns_zonemgr_t *zmgr) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "sign_apex:update_sigs -> %s\n", + dns_result_totext(result)); + goto failure; + } - return (zmgr->serialqueryrate); + failure: + for (i = 0; i < nkeys; i++) + dst_key_free(&zone_keys[i]); + return (result); } +/* + * Prevent the zone entering a inconsistent state where + * NSEC only DNSKEYs are present with NSEC3 chains. + * See update.c:check_dnssec() + */ static isc_boolean_t -dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, - isc_sockaddr_t *local, isc_time_t *now) +dnskey_sane(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, + dns_diff_t *diff) { - unsigned int i; - isc_rwlocktype_t locktype; isc_result_t result; - isc_uint32_t seconds = isc_time_seconds(now); + dns_difftuple_t *tuple; + isc_boolean_t nseconly = ISC_FALSE, nsec3 = ISC_FALSE; + dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + /* Scan the tuples for an NSEC-only DNSKEY */ + for (tuple = ISC_LIST_HEAD(diff->tuples); + tuple != NULL; + tuple = ISC_LIST_NEXT(tuple, link)) { + isc_uint8_t alg; + if (tuple->rdata.type != dns_rdatatype_dnskey || + tuple->op != DNS_DIFFOP_ADD) + continue; - locktype = isc_rwlocktype_read; - RWLOCK(&zmgr->rwlock, locktype); - for (i = 0; i < UNREACH_CHACHE_SIZE; i++) { - if (zmgr->unreachable[i].expire >= seconds && - isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && - isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) { - result = isc_rwlock_tryupgrade(&zmgr->rwlock); - if (result == ISC_R_SUCCESS) { - locktype = isc_rwlocktype_write; - zmgr->unreachable[i].last = seconds; - } + alg = tuple->rdata.data[3]; + if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 || + alg == DST_ALG_DSA || alg == DST_ALG_ECC) { + nseconly = ISC_TRUE; break; } } - RWUNLOCK(&zmgr->rwlock, locktype); - return (ISC_TF(i < UNREACH_CHACHE_SIZE)); -} -void -dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, - isc_sockaddr_t *local, isc_time_t *now) -{ - isc_uint32_t seconds = isc_time_seconds(now); - isc_uint32_t last = seconds; - unsigned int i, slot = UNREACH_CHACHE_SIZE, oldest = 0; + /* Check existing DB for NSEC-only DNSKEY */ + if (!nseconly) + CHECK(dns_nsec_nseconly(db, ver, &nseconly)); - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + /* Check existing DB for NSEC3 */ + if (!nsec3) + CHECK(dns_nsec3_activex(db, ver, ISC_FALSE, + privatetype, &nsec3)); - RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); - for (i = 0; i < UNREACH_CHACHE_SIZE; i++) { - /* Existing entry? */ - if (isc_sockaddr_equal(&zmgr->unreachable[i].remote, remote) && - isc_sockaddr_equal(&zmgr->unreachable[i].local, local)) - break; - /* Empty slot? */ - if (zmgr->unreachable[i].expire < seconds) - slot = i; - /* Least recently used slot? */ - if (zmgr->unreachable[i].last < last) { - last = zmgr->unreachable[i].last; - oldest = i; - } - } - if (i < UNREACH_CHACHE_SIZE) { - /* - * Found a existing entry. Update the expire timer and - * last usage timestamps. - */ - zmgr->unreachable[i].expire = seconds + UNREACH_HOLD_TIME; - zmgr->unreachable[i].last = seconds; - } else if (slot != UNREACH_CHACHE_SIZE) { - /* - * Found a empty slot. Add a new entry to the cache. - */ - zmgr->unreachable[slot].expire = seconds + UNREACH_HOLD_TIME; - zmgr->unreachable[slot].last = seconds; - zmgr->unreachable[slot].remote = *remote; - zmgr->unreachable[slot].local = *local; - } else { - /* - * Replace the least recently used entry in the cache. - */ - zmgr->unreachable[oldest].expire = seconds + UNREACH_HOLD_TIME; - zmgr->unreachable[oldest].last = seconds; - zmgr->unreachable[oldest].remote = *remote; - zmgr->unreachable[oldest].local = *local; + /* Refuse to allow NSEC3 with NSEC-only keys */ + if (nseconly && nsec3) { + dns_zone_log(zone, ISC_LOG_ERROR, + "NSEC only DNSKEYs and NSEC3 chains not allowed"); + goto failure; } - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); + + return (ISC_TRUE); + + failure: + return (ISC_FALSE); } -void -dns_zone_forcereload(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); +static isc_result_t +clean_nsec3param(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, + dns_diff_t *diff) +{ + isc_result_t result; + dns_dbnode_t *node = NULL; + dns_rdataset_t rdataset; + + dns_rdataset_init(&rdataset); + CHECK(dns_db_getoriginnode(db, &node)); + + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, + dns_rdatatype_none, 0, &rdataset, NULL); + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (result != ISC_R_NOTFOUND) + goto failure; - if (zone->type == dns_zone_master) - return; + result = dns_nsec3param_deletechains(db, ver, zone, diff); - LOCK_ZONE(zone); - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_FORCEXFER); - UNLOCK_ZONE(zone); - dns_zone_refresh(zone); + failure: + if (node != NULL) + dns_db_detachnode(db, &node); + return (result); } -isc_boolean_t -dns_zone_isforced(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); +/* + * Given an RRSIG rdataset and an algorithm, determine whether there + * are any signatures using that algorithm. + */ +static isc_boolean_t +signed_with_alg(dns_rdataset_t *rdataset, dns_secalg_t alg) { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_rrsig_t rrsig; + isc_result_t result; - return (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)); -} + REQUIRE(rdataset == NULL || rdataset->type == dns_rdatatype_rrsig); + if (rdataset == NULL || !dns_rdataset_isassociated(rdataset)) { + return (ISC_FALSE); + } -isc_result_t -dns_zone_setstatistics(dns_zone_t *zone, isc_boolean_t on) { - /* - * This function is obsoleted. - */ - UNUSED(zone); - UNUSED(on); - return (ISC_R_NOTIMPLEMENTED); -} + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) + { + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &rrsig, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_rdata_reset(&rdata); + if (rrsig.algorithm == alg) + return (ISC_TRUE); + } -isc_uint64_t * -dns_zone_getstatscounters(dns_zone_t *zone) { - /* - * This function is obsoleted. - */ - UNUSED(zone); - return (NULL); + return (ISC_FALSE); } -void -dns_zone_setstats(dns_zone_t *zone, isc_stats_t *stats) { - REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(zone->stats == NULL); +static isc_result_t +add_chains(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, + dns_diff_t *diff) +{ + dns_name_t *origin; + isc_boolean_t build_nsec3; + isc_result_t result; - LOCK_ZONE(zone); - zone->stats = NULL; - isc_stats_attach(stats, &zone->stats); - UNLOCK_ZONE(zone); + origin = dns_db_origin(db); + CHECK(dns_private_chains(db, ver, zone->privatetype, NULL, + &build_nsec3)); + if (build_nsec3) + CHECK(dns_nsec3_addnsec3sx(db, ver, origin, zone->minimum, + ISC_FALSE, zone->privatetype, diff)); + CHECK(updatesecure(db, ver, origin, zone->minimum, ISC_TRUE, diff)); + + failure: + return (result); } -void -dns_zone_setrequeststats(dns_zone_t *zone, isc_stats_t *stats) { +static void +zone_rekey(dns_zone_t *zone) { + isc_result_t result; + dns_db_t *db = NULL; + dns_dbnode_t *node = NULL; + dns_dbversion_t *ver = NULL; + dns_rdataset_t soaset, soasigs, keyset, keysigs; + dns_dnsseckeylist_t dnskeys, keys, rmkeys; + dns_dnsseckey_t *key; + dns_diff_t diff, sig_diff; + isc_boolean_t commit = ISC_FALSE, newactive = ISC_FALSE; + isc_boolean_t fullsign; + dns_ttl_t ttl = 3600; + const char *dir; + isc_mem_t *mctx; + isc_stdtime_t now; + isc_time_t timenow; + isc_interval_t ival; + char timebuf[80]; + REQUIRE(DNS_ZONE_VALID(zone)); - LOCK_ZONE(zone); - if (zone->requeststats_on && stats == NULL) - zone->requeststats_on = ISC_FALSE; - else if (!zone->requeststats_on && stats != NULL) { - if (zone->requeststats == NULL) { - isc_stats_attach(stats, &zone->requeststats); - zone->requeststats_on = ISC_TRUE; - } - } - UNLOCK_ZONE(zone); + ISC_LIST_INIT(dnskeys); + ISC_LIST_INIT(keys); + ISC_LIST_INIT(rmkeys); + dns_rdataset_init(&soaset); + dns_rdataset_init(&soasigs); + dns_rdataset_init(&keyset); + dns_rdataset_init(&keysigs); + dir = dns_zone_getkeydirectory(zone); + mctx = zone->mctx; + dns_diff_init(mctx, &diff); + dns_diff_init(mctx, &sig_diff); - return; -} + CHECK(dns_zone_getdb(zone, &db)); + CHECK(dns_db_newversion(db, &ver)); + CHECK(dns_db_getoriginnode(db, &node)); + + dns_zone_log(zone, ISC_LOG_INFO, "reconfiguring zone keys"); + + /* Get the SOA record's TTL */ + CHECK(dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, + dns_rdatatype_none, 0, &soaset, &soasigs)); + ttl = soaset.ttl; + dns_rdataset_disassociate(&soaset); + + /* Get the DNSKEY rdataset */ + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, + dns_rdatatype_none, 0, &keyset, &keysigs); + if (result == ISC_R_SUCCESS) { + ttl = keyset.ttl; + result = dns_dnssec_keylistfromrdataset(&zone->origin, dir, + mctx, &keyset, + &keysigs, &soasigs, + ISC_FALSE, ISC_FALSE, + &dnskeys); + /* Can't get keys for some reason; try again later. */ + if (result != ISC_R_SUCCESS) + goto trylater; + } else if (result != ISC_R_NOTFOUND) + goto failure; -isc_stats_t * -dns_zone_getrequeststats(dns_zone_t *zone) { /* - * We don't lock zone for efficiency reason. This is not catastrophic - * because requeststats must always be valid when requeststats_on is - * true. - * Some counters may be incremented while requeststats_on is becoming - * false, or some cannot be incremented just after the statistics are - * installed, but it shouldn't matter much in practice. + * True when called from "rndc sign". Indicates the zone should be + * fully signed now. */ - if (zone->requeststats_on) - return (zone->requeststats); - else - return (NULL); -} - -void -dns_zone_dialup(dns_zone_t *zone) { + fullsign = ISC_TF(DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_FULLSIGN) != 0); - REQUIRE(DNS_ZONE_VALID(zone)); + result = dns_dnssec_findmatchingkeys(&zone->origin, dir, mctx, &keys); + if (result == ISC_R_SUCCESS) { + isc_boolean_t check_ksk; + check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK); - zone_debuglog(zone, "dns_zone_dialup", 3, - "notify = %d, refresh = %d", - DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY), - DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)); + result = dns_dnssec_updatekeys(&dnskeys, &keys, &rmkeys, + &zone->origin, ttl, &diff, + ISC_TF(!check_ksk), + mctx, logmsg); - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY)) - dns_zone_notify(zone); - if (zone->type != dns_zone_master && - DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)) - dns_zone_refresh(zone); -} + /* Keys couldn't be updated for some reason; + * try again later. */ + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, "zone_rekey:" + "couldn't update zone keys: %s", + isc_result_totext(result)); + goto trylater; + } -void -dns_zone_setdialup(dns_zone_t *zone, dns_dialuptype_t dialup) { - REQUIRE(DNS_ZONE_VALID(zone)); + /* See if any pre-existing keys have newly become active */ + for (key = ISC_LIST_HEAD(dnskeys); + key != NULL; + key = ISC_LIST_NEXT(key, link)) { + if (key->first_sign) { + newactive = ISC_TRUE; + break; + } + } - LOCK_ZONE(zone); - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_DIALNOTIFY | - DNS_ZONEFLG_DIALREFRESH | - DNS_ZONEFLG_NOREFRESH); - switch (dialup) { - case dns_dialuptype_no: - break; - case dns_dialuptype_yes: - DNS_ZONE_SETFLAG(zone, (DNS_ZONEFLG_DIALNOTIFY | - DNS_ZONEFLG_DIALREFRESH | - DNS_ZONEFLG_NOREFRESH)); - break; - case dns_dialuptype_notify: - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DIALNOTIFY); - break; - case dns_dialuptype_notifypassive: - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DIALNOTIFY); - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOREFRESH); - break; - case dns_dialuptype_refresh: - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DIALREFRESH); - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOREFRESH); - break; - case dns_dialuptype_passive: - DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOREFRESH); - break; - default: - INSIST(0); + if ((newactive || fullsign || !ISC_LIST_EMPTY(diff.tuples)) && + dnskey_sane(zone, db, ver, &diff)) { + CHECK(dns_diff_apply(&diff, db, ver)); + CHECK(clean_nsec3param(zone, db, ver, &diff)); + CHECK(add_signing_records(db, zone->privatetype, ver, + &diff)); + CHECK(increment_soa_serial(db, ver, &diff, mctx)); + CHECK(add_chains(zone, db, ver, &diff)); + CHECK(sign_apex(zone, db, ver, &diff, &sig_diff)); + CHECK(zone_journal(zone, &sig_diff, "zone_rekey")); + commit = ISC_TRUE; + } } - UNLOCK_ZONE(zone); -} -isc_result_t -dns_zone_setkeydirectory(dns_zone_t *zone, const char *directory) { - isc_result_t result = ISC_R_SUCCESS; + dns_db_closeversion(db, &ver, commit); - REQUIRE(DNS_ZONE_VALID(zone)); + if (commit) { + isc_time_t timenow; + dns_difftuple_t *tuple; + isc_boolean_t newkey = ISC_FALSE; + isc_boolean_t newalg = ISC_FALSE; - LOCK_ZONE(zone); - result = dns_zone_setstring(zone, &zone->keydirectory, directory); - UNLOCK_ZONE(zone); + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); - return (result); -} + zone_needdump(zone, DNS_DUMP_DELAY); -const char * -dns_zone_getkeydirectory(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); + TIME_NOW(&timenow); + zone_settimer(zone, &timenow); - return (zone->keydirectory); -} + /* + * Has a new key become active? If so, is it for + * a new algorithm? + */ + for (tuple = ISC_LIST_HEAD(sig_diff.tuples); + tuple != NULL; + tuple = ISC_LIST_NEXT(tuple, link)) { + dns_rdata_dnskey_t dnskey; -unsigned int -dns_zonemgr_getcount(dns_zonemgr_t *zmgr, int state) { - dns_zone_t *zone; - unsigned int count = 0; + if (tuple->rdata.type != dns_rdatatype_dnskey) + continue; - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + newkey = ISC_TRUE; + if (!dns_rdataset_isassociated(&keysigs)) { + newalg = ISC_TRUE; + break; + } - RWLOCK(&zmgr->rwlock, isc_rwlocktype_read); - switch (state) { - case DNS_ZONESTATE_XFERRUNNING: - for (zone = ISC_LIST_HEAD(zmgr->xfrin_in_progress); - zone != NULL; - zone = ISC_LIST_NEXT(zone, statelink)) - count++; - break; - case DNS_ZONESTATE_XFERDEFERRED: - for (zone = ISC_LIST_HEAD(zmgr->waiting_for_xfrin); - zone != NULL; - zone = ISC_LIST_NEXT(zone, statelink)) - count++; - break; - case DNS_ZONESTATE_SOAQUERY: - for (zone = ISC_LIST_HEAD(zmgr->zones); - zone != NULL; - zone = ISC_LIST_NEXT(zone, link)) - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH)) - count++; - break; - case DNS_ZONESTATE_ANY: - for (zone = ISC_LIST_HEAD(zmgr->zones); - zone != NULL; - zone = ISC_LIST_NEXT(zone, link)) { - dns_view_t *view = zone->view; - if (view != NULL && strcmp(view->name, "_bind") == 0) - continue; - count++; + result = dns_rdata_tostruct(&tuple->rdata, + &dnskey, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (!signed_with_alg(&keysigs, + dnskey.algorithm)) { + newalg = ISC_TRUE; + break; + } } - break; - default: - INSIST(0); - } - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); + /* + * If we found a new algorithm, we need to sign the + * zone fully. If there's a new key, but it's for an + * already-existing algorithm, then the zone signing + * can be handled incrementally. + */ + if (newkey && !newalg) + set_resigntime(zone); - return (count); -} + /* Remove any signatures from removed keys. */ + if (!ISC_LIST_EMPTY(rmkeys)) { + for (key = ISC_LIST_HEAD(rmkeys); + key != NULL; + key = ISC_LIST_NEXT(key, link)) { + result = zone_signwithkey(zone, + dst_key_alg(key->key), + dst_key_id(key->key), + ISC_TRUE); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_signwithkey failed: %s", + dns_result_totext(result)); + } + } + } + + + if (fullsign) { + /* + * "rndc sign" was called, so we now sign the zone + * with all active keys, whether they're new or not. + */ + for (key = ISC_LIST_HEAD(dnskeys); + key != NULL; + key = ISC_LIST_NEXT(key, link)) { + if (!key->force_sign && !key->hint_sign) + continue; + + result = zone_signwithkey(zone, + dst_key_alg(key->key), + dst_key_id(key->key), + ISC_FALSE); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_signwithkey failed: %s", + dns_result_totext(result)); + } + } + } else if (newalg) { + /* + * We haven't been told to sign fully, but a new + * algorithm was added to the DNSKEY. We sign + * the full zone, but only with the newly-added + * keys. + */ + for (tuple = ISC_LIST_HEAD(sig_diff.tuples); + tuple != NULL; + tuple = ISC_LIST_NEXT(tuple, link)) { + dns_rdata_dnskey_t dnskey; + dns_secalg_t algorithm; + isc_region_t r; + isc_uint16_t keyid; + + if (tuple->rdata.type != dns_rdatatype_dnskey || + tuple->op == DNS_DIFFOP_DEL) + continue; + + result = dns_rdata_tostruct(&tuple->rdata, + &dnskey, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_rdata_toregion(&tuple->rdata, &r); + algorithm = dnskey.algorithm; + keyid = dst_region_computeid(&r, algorithm); + + result = zone_signwithkey(zone, algorithm, + keyid, ISC_FALSE); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_signwithkey failed: %s", + dns_result_totext(result)); + } + } + } -isc_result_t -dns_zone_checknames(dns_zone_t *zone, dns_name_t *name, dns_rdata_t *rdata) { - isc_boolean_t ok = ISC_TRUE; - isc_boolean_t fail = ISC_FALSE; - char namebuf[DNS_NAME_FORMATSIZE]; - char namebuf2[DNS_NAME_FORMATSIZE]; - char typebuf[DNS_RDATATYPE_FORMATSIZE]; - int level = ISC_LOG_WARNING; - dns_name_t bad; + /* + * Clear fullsign flag, if it was set, so we don't do + * another full signing next time + */ + zone->keyopts &= ~DNS_ZONEKEY_FULLSIGN; - REQUIRE(DNS_ZONE_VALID(zone)); + /* + * Cause the zone to add/delete NSEC3 chains for the + * deferred NSEC3PARAM changes. + */ + for (tuple = ISC_LIST_HEAD(sig_diff.tuples); + tuple != NULL; + tuple = ISC_LIST_NEXT(tuple, link)) { + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_nsec3param_t nsec3param; - if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES)) - return (ISC_R_SUCCESS); + if (tuple->rdata.type != zone->privatetype || + tuple->op != DNS_DIFFOP_ADD) + continue; - if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL)) { - level = ISC_LOG_ERROR; - fail = ISC_TRUE; - } + if (!dns_nsec3param_fromprivate(&tuple->rdata, &rdata, + buf, sizeof(buf))) + continue; + result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (nsec3param.flags == 0) + continue; - ok = dns_rdata_checkowner(name, rdata->rdclass, rdata->type, ISC_TRUE); - if (!ok) { - dns_name_format(name, namebuf, sizeof(namebuf)); - dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf)); - dns_zone_log(zone, level, "%s/%s: %s", namebuf, typebuf, - dns_result_totext(DNS_R_BADOWNERNAME)); - if (fail) - return (DNS_R_BADOWNERNAME); + result = zone_addnsec3chain(zone, &nsec3param); + if (result != ISC_R_SUCCESS) { + dns_zone_log(zone, ISC_LOG_ERROR, + "zone_addnsec3chain failed: %s", + dns_result_totext(result)); + } + } + UNLOCK_ZONE(zone); } - dns_name_init(&bad, NULL); - ok = dns_rdata_checknames(rdata, name, &bad); - if (!ok) { - dns_name_format(name, namebuf, sizeof(namebuf)); - dns_name_format(&bad, namebuf2, sizeof(namebuf2)); - dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf)); - dns_zone_log(zone, level, "%s/%s: %s: %s ", namebuf, typebuf, - namebuf2, dns_result_totext(DNS_R_BADNAME)); - if (fail) - return (DNS_R_BADNAME); - } + isc_stdtime_get(&now); + TIME_NOW(&timenow); + isc_time_settoepoch(&zone->refreshkeytime); + for (key = ISC_LIST_HEAD(dnskeys); + key != NULL; + key = ISC_LIST_NEXT(key, link)) { + isc_stdtime_t then; + isc_time_t timethen; - return (ISC_R_SUCCESS); -} + /* + * If we are doing automatic key maintenance and the + * key metadata indicates there is a key change event + * scheduled in the future, set the key refresh timer. + */ + if (!DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN)) + break; -void -dns_zone_setcheckmx(dns_zone_t *zone, dns_checkmxfunc_t checkmx) { - REQUIRE(DNS_ZONE_VALID(zone)); - zone->checkmx = checkmx; -} + then = now; + result = next_keyevent(key->key, &then); + if (result != ISC_R_SUCCESS) + continue; -void -dns_zone_setchecksrv(dns_zone_t *zone, dns_checksrvfunc_t checksrv) { - REQUIRE(DNS_ZONE_VALID(zone)); - zone->checksrv = checksrv; -} + DNS_ZONE_TIME_ADD(&timenow, then - now, &timethen); + LOCK_ZONE(zone); + if (isc_time_isepoch(&zone->refreshkeytime) || + isc_time_compare(&timethen, &zone->refreshkeytime) < 0) { + zone->refreshkeytime = timethen; + zone_settimer(zone, &timenow); + } + UNLOCK_ZONE(zone); + } -void -dns_zone_setcheckns(dns_zone_t *zone, dns_checknsfunc_t checkns) { - REQUIRE(DNS_ZONE_VALID(zone)); - zone->checkns = checkns; -} + /* + * If no key event is scheduled, we should still check the key + * repository for updates every so often. (Currently this is + * hard-coded to 12 hours, but it could be configurable.) + */ + if (isc_time_isepoch(&zone->refreshkeytime)) + DNS_ZONE_TIME_ADD(&timenow, (3600 * 12), &zone->refreshkeytime); -void -dns_zone_setisself(dns_zone_t *zone, dns_isselffunc_t isself, void *arg) { - REQUIRE(DNS_ZONE_VALID(zone)); + isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80); + dns_zone_log(zone, ISC_LOG_INFO, "next key event: %s", timebuf); - LOCK_ZONE(zone); - zone->isself = isself; - zone->isselfarg = arg; - UNLOCK_ZONE(zone); -} + failure: + dns_diff_clear(&diff); + dns_diff_clear(&sig_diff); -void -dns_zone_setnotifydelay(dns_zone_t *zone, isc_uint32_t delay) { - REQUIRE(DNS_ZONE_VALID(zone)); + clear_keylist(&dnskeys, mctx); + clear_keylist(&keys, mctx); + clear_keylist(&rmkeys, mctx); + + if (ver != NULL) + dns_db_closeversion(db, &ver, ISC_FALSE); + if (dns_rdataset_isassociated(&keyset)) + dns_rdataset_disassociate(&keyset); + if (dns_rdataset_isassociated(&keysigs)) + dns_rdataset_disassociate(&keysigs); + if (dns_rdataset_isassociated(&soasigs)) + dns_rdataset_disassociate(&soasigs); + if (node != NULL) + dns_db_detachnode(db, &node); + if (db != NULL) + dns_db_detach(&db); + return; - LOCK_ZONE(zone); - zone->notifydelay = delay; - UNLOCK_ZONE(zone); + trylater: + isc_interval_set(&ival, HOUR, 0); + isc_time_nowplusinterval(&zone->refreshkeytime, &ival); + goto failure; } -isc_uint32_t -dns_zone_getnotifydelay(dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); +void +dns_zone_rekey(dns_zone_t *zone, isc_boolean_t fullsign) { + isc_time_t now; - return (zone->notifydelay); -} + if (zone->type == dns_zone_master && zone->task != NULL) { + LOCK_ZONE(zone); -isc_result_t -dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, - isc_uint16_t keyid, isc_boolean_t delete) -{ - isc_result_t result; - REQUIRE(DNS_ZONE_VALID(zone)); + if (fullsign) + zone->keyopts |= DNS_ZONEKEY_FULLSIGN; - dns_zone_log(zone, ISC_LOG_NOTICE, - "dns_zone_signwithkey(algorithm=%u, keyid=%u)", - algorithm, keyid); - LOCK_ZONE(zone); - result = zone_signwithkey(zone, algorithm, keyid, delete); - UNLOCK_ZONE(zone); + TIME_NOW(&now); + zone->refreshkeytime = now; + zone_settimer(zone, &now); - return (result); + UNLOCK_ZONE(zone); + } } -static const char *hex = "0123456789ABCDEF"; - isc_result_t -dns_zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) { +dns_zone_nscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, + unsigned int *errors) +{ isc_result_t result; - char salt[255*2+1]; - unsigned int i, j; + dns_dbnode_t *node = NULL; REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(errors != NULL); - if (nsec3param->salt_length != 0) { - INSIST((nsec3param->salt_length * 2U) < sizeof(salt)); - for (i = 0, j = 0; i < nsec3param->salt_length; i++) { - salt[j++] = hex[(nsec3param->salt[i] >> 4) & 0xf]; - salt[j++] = hex[nsec3param->salt[i] & 0xf]; - } - salt[j] = '\0'; - } else - strcpy(salt, "-"); - dns_zone_log(zone, ISC_LOG_NOTICE, - "dns_zone_addnsec3chain(hash=%u, iterations=%u, salt=%s)", - nsec3param->hash, nsec3param->iterations, - salt); - LOCK_ZONE(zone); - result = zone_addnsec3chain(zone, nsec3param); - UNLOCK_ZONE(zone); - + result = dns_db_getoriginnode(db, &node); + if (result != ISC_R_SUCCESS) + return (result); + result = zone_count_ns_rr(zone, db, node, version, NULL, errors, + ISC_FALSE); + dns_db_detachnode(db, &node); return (result); } void -dns_zone_setnodes(dns_zone_t *zone, isc_uint32_t nodes) { - REQUIRE(DNS_ZONE_VALID(zone)); - - if (nodes == 0) - nodes = 1; - zone->nodes = nodes; -} - -void -dns_zone_setsignatures(dns_zone_t *zone, isc_uint32_t signatures) { - REQUIRE(DNS_ZONE_VALID(zone)); - - /* - * We treat signatures as a signed value so explicitly - * limit its range here. - */ - if (signatures > ISC_INT32_MAX) - signatures = ISC_INT32_MAX; - else if (signatures == 0) - signatures = 1; - zone->signatures = signatures; -} - -void -dns_zone_setprivatetype(dns_zone_t *zone, dns_rdatatype_t type) { +dns_zone_setadded(dns_zone_t *zone, isc_boolean_t added) { REQUIRE(DNS_ZONE_VALID(zone)); - zone->privatetype = type; + LOCK_ZONE(zone); + zone->added = added; + UNLOCK_ZONE(zone); } -dns_rdatatype_t -dns_zone_getprivatetype(dns_zone_t *zone) { +isc_boolean_t +dns_zone_getadded(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); - return (zone->privatetype); + return (zone->added); } -static isc_result_t -zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid, - isc_boolean_t delete) +isc_result_t +dns_zone_dlzpostload(dns_zone_t *zone, dns_db_t *db) { - dns_signing_t *signing; - dns_signing_t *current; - isc_result_t result = ISC_R_SUCCESS; - isc_time_t now; - - signing = isc_mem_get(zone->mctx, sizeof *signing); - if (signing == NULL) - return (ISC_R_NOMEMORY); - - signing->magic = 0; - signing->db = NULL; - signing->dbiterator = NULL; - signing->algorithm = algorithm; - signing->keyid = keyid; - signing->delete = delete; - signing->done = ISC_FALSE; - - TIME_NOW(&now); - - for (current = ISC_LIST_HEAD(zone->signing); - current != NULL; - current = ISC_LIST_NEXT(current, link)) { - if (current->db == zone->db && - current->algorithm == signing->algorithm && - current->keyid == signing->keyid) { - if (current->delete != signing->delete) - current->done = ISC_TRUE; - else - goto cleanup; - } - } - - if (zone->db != NULL) { - dns_db_attach(zone->db, &signing->db); - result = dns_db_createiterator(signing->db, 0, - &signing->dbiterator); - - if (result == ISC_R_SUCCESS) - result = dns_dbiterator_first(signing->dbiterator); - if (result == ISC_R_SUCCESS) { - dns_dbiterator_pause(signing->dbiterator); - ISC_LIST_INITANDAPPEND(zone->signing, signing, link); - signing = NULL; - if (isc_time_isepoch(&zone->signingtime)) { - zone->signingtime = now; - if (zone->task != NULL) - zone_settimer(zone, &now); - } - } - } else - result = ISC_R_NOTFOUND; + isc_time_t loadtime; + isc_result_t result; + TIME_NOW(&loadtime); - cleanup: - if (signing != NULL) { - if (signing->db != NULL) - dns_db_detach(&signing->db); - if (signing->dbiterator != NULL) - dns_dbiterator_destroy(&signing->dbiterator); - isc_mem_put(zone->mctx, signing, sizeof *signing); - } - return (result); + LOCK_ZONE(zone); + result = zone_postload(zone, db, loadtime, ISC_R_SUCCESS); + UNLOCK_ZONE(zone); + return result; } diff --git a/lib/export/Makefile.in b/lib/export/Makefile.in new file mode 100644 index 0000000..5a9e633 --- /dev/null +++ b/lib/export/Makefile.in @@ -0,0 +1,27 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ + +# Note: the order of SUBDIRS is important. +# Attempt to disable parallel processing. +.NOTPARALLEL: +.NO_PARALLEL: +SUBDIRS = isc dns isccfg irs samples +TARGETS = + +@BIND9_MAKE_RULES@ diff --git a/lib/export/dns/Makefile.in b/lib/export/dns/Makefile.in new file mode 100644 index 0000000..15b0d3f --- /dev/null +++ b/lib/export/dns/Makefile.in @@ -0,0 +1,179 @@ +# Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.8 2010-12-23 04:07:59 marka Exp $ + +top_srcdir = @top_srcdir@ +srcdir = @top_srcdir@/lib/dns +export_srcdir = @top_srcdir@/lib/export + +# Attempt to disable parallel processing. +.NOTPARALLEL: +.NO_PARALLEL: + +@BIND9_VERSION@ + +@LIBDNS_API@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I. -Iinclude ${DNS_INCLUDES} -I${export_srcdir}/isc/include \ + ${ISC_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@ + +CDEFINES = -DUSE_MD5 @USE_OPENSSL@ @USE_GSSAPI@ + +CWARNINGS = + +ISCLIBS = ../isc/libisc.@A@ + +ISCDEPLIBS = ../isc/libisc.@A@ + +LIBS = @LIBS@ + +# Alphabetically + +OPENSSLLINKOBJS = openssl_link.@O@ openssldh_link.@O@ openssldsa_link.@O@ \ + opensslgost_link.@O@ opensslrsa_link.@O@ + +DSTOBJS = @OPENSSLLINKOBJS@ \ + dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \ + gssapi_link.@O@ gssapictx.@O@ hmac_link.@O@ key.@O@ + +DNSOBJS = acl.@O@ adb.@O@ byaddr.@O@ \ + cache.@O@ callbacks.@O@ client.@O@ compress.@O@ \ + db.@O@ dbiterator.@O@ diff.@O@ dispatch.@O@ dlz.@O@ dnssec.@O@ \ + ds.@O@ \ + forward.@O@ iptable.@O@ \ + keytable.@O@ \ + lib.@O@ log.@O@ \ + master.@O@ masterdump.@O@ message.@O@ \ + name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ \ + peer.@O@ portlist.@O@ \ + rbt.@O@ rbtdb.@O@ rcode.@O@ rdata.@O@ \ + rdatalist.@O@ rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ \ + request.@O@ resolver.@O@ result.@O@ soa.@O@ stats.@O@ \ + tcpmsg.@O@ time.@O@ tsec.@O@ tsig.@O@ ttl.@O@ \ + validator.@O@ version.@O@ view.@O@ +PORTDNSOBJS = ecdb.@O@ + +OBJS= ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} ${PORTDNSOBJS} + +# Alphabetically + +OPENSSLLINKSRCS = openssl_link.c openssldh_link.c openssldsa_link.c \ + opensslgost_link.c opensslrsa_link.c + +DSTSRCS = @OPENSSLLINKSRCS@ \ + dst_api.c dst_lib.c dst_parse.c \ + dst_result.c gssapi_link.c gssapictx.c \ + hmac_link.c key.c + +DNSSRCS = acl.c adb.c byaddr.c \ + cache.c callbacks.c client.c compress.c \ + db.c dbiterator.c diff.c dispatch.c dlz.c dnssec.c ds.c \ + forward.c iptable.c \ + keytable.c \ + lib.c log.c \ + master.c masterdump.c message.c \ + name.c ncache.c nsec.c nsec3.c \ + peer.c portlist.c \ + rbt.c rbtdb.c rcode.c rdata.c \ + rdatalist.c rdataset.c rdatasetiter.c rdataslab.c \ + request.c res.c resolver.c result.c soa.c stats.c \ + tcpmsg.c time.c tsec.c tsig.c ttl.c \ + validator.c version.c view.c +PORTDNSSRCS = ecdb.c + +SRCS = ${DSTSRCS} ${DNSSRCS} ${PORTDNSSRCS} + +SUBDIRS = include +TARGETS = include/dns/enumtype.h include/dns/enumclass.h \ + include/dns/rdatastruct.h timestamp + +DEPENDEXTRA = ./gen -F include/dns/rdatastruct.h \ + -s ${srcdir} -d >> Makefile ; + +@BIND9_MAKE_RULES@ + +version.@O@: ${srcdir}/version.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DVERSION=\"${VERSION}\" \ + -DLIBINTERFACE=${LIBINTERFACE} \ + -DLIBREVISION=${LIBREVISION} \ + -DLIBAGE=${LIBAGE} \ + -c ${srcdir}/version.c + +libdns.@SA@: ${OBJS} + ${AR} ${ARFLAGS} $@ ${OBJS} + ${RANLIB} $@ + +libdns.la: ${OBJS} + ${LIBTOOL_MODE_LINK} \ + ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libdns.la \ + -rpath ${export_libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${ISCLIBS} @DNS_CRYPTO_LIBS@ ${LIBS} + +timestamp: libdns.@A@ + touch timestamp + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_libdir} + +install:: timestamp installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libdns.@A@ \ + ${DESTDIR}${export_libdir} + +clean distclean:: + rm -f libdns.@A@ timestamp + rm -f gen code.h include/dns/enumtype.h include/dns/enumclass.h + rm -f include/dns/rdatastruct.h + +newrr:: + rm -f code.h include/dns/enumtype.h include/dns/enumclass.h + rm -f include/dns/rdatastruct.h + +include: include/dns/enumtype.h include/dns/enumclass.h \ + include/dns/rdatastruct.h + +rdata.@O@: code.h + +include/dns/enumtype.h: gen + ./gen -s ${srcdir} -t > $@ + +include/dns/enumclass.h: gen + ./gen -s ${srcdir} -c > $@ + +include/dns/rdatastruct.h: gen \ + ${srcdir}/rdata/rdatastructpre.h \ + ${srcdir}/rdata/rdatastructsuf.h + ./gen -s ${srcdir} -i \ + -P ${srcdir}/rdata/rdatastructpre.h \ + -S ${srcdir}/rdata/rdatastructsuf.h > $@ + +code.h: gen + ./gen -s ${srcdir} > code.h + +gen: ${srcdir}/gen.c + ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ ${srcdir}/gen.c ${LIBS} + +#We don't need rbtdb64 for this library +#rbtdb64.@O@: rbtdb.c + +depend: include/dns/enumtype.h include/dns/enumclass.h \ + include/dns/rdatastruct.h code.h +subdirs: include/dns/enumtype.h include/dns/enumclass.h \ + include/dns/rdatastruct.h code.h +${OBJS}: include/dns/enumtype.h include/dns/enumclass.h \ + include/dns/rdatastruct.h diff --git a/lib/export/dns/include/Makefile.in b/lib/export/dns/include/Makefile.in new file mode 100644 index 0000000..ecd9c8a --- /dev/null +++ b/lib/export/dns/include/Makefile.in @@ -0,0 +1,23 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ + +SUBDIRS = dns dst +TARGETS = + +@BIND9_MAKE_RULES@ diff --git a/lib/export/dns/include/dns/Makefile.in b/lib/export/dns/include/dns/Makefile.in new file mode 100644 index 0000000..ccaae41 --- /dev/null +++ b/lib/export/dns/include/dns/Makefile.in @@ -0,0 +1,56 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.4 2009-09-18 07:18:04 jinmei Exp $ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_VERSION@ + +HEADERS = acl.h adb.h byaddr.h \ + cache.h callbacks.h cert.h client.h compress.h \ + db.h dbiterator.h diff.h dispatch.h dlz.h dnssec.h \ + ds.h events.h fixedname.h ecdb.h \ + forward.h iptable.h \ + keytable.h keyvalues.h \ + lib.h log.h \ + master.h masterdump.h message.h \ + name.h ncache.h nsec.h nsec3.h \ + peer.h portlist.h \ + rbt.h rcode.h rdata.h rdataclass.h \ + rdatalist.h rdataset.h rdatasetiter.h rdataslab.h rdatatype.h \ + request.h resolver.h result.h \ + secalg.h secproto.h soa.h stats.h \ + tcpmsg.h time.h tsec.h tsig.h ttl.h types.h \ + validator.h version.h view.h + +GENHEADERS = enumclass.h enumtype.h rdatastruct.h + +SUBDIRS = +TARGETS = + +@BIND9_MAKE_RULES@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_includedir}/dns + +install:: installdirs + for i in ${HEADERS}; do \ + ${INSTALL_DATA} ${top_srcdir}/lib/dns/include/dns/$$i \ + ${DESTDIR}${export_includedir}/dns ; \ + done + for i in ${GENHEADERS}; do \ + ${INSTALL_DATA} $$i ${DESTDIR}${export_includedir}/dns ; \ + done diff --git a/lib/export/dns/include/dst/Makefile.in b/lib/export/dns/include/dst/Makefile.in new file mode 100644 index 0000000..cebc726 --- /dev/null +++ b/lib/export/dns/include/dst/Makefile.in @@ -0,0 +1,36 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_VERSION@ + +HEADERS = dst.h gssapi.h lib.h result.h + +SUBDIRS = +TARGETS = + +@BIND9_MAKE_RULES@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_includedir}/dst + +install:: installdirs + for i in ${HEADERS}; do \ + ${INSTALL_DATA} ${top_srcdir}/lib/dns/include/dst/$$i \ + ${DESTDIR}${export_includedir}/dst ; \ + done diff --git a/lib/export/irs/Makefile.in b/lib/export/irs/Makefile.in new file mode 100644 index 0000000..aad9400 --- /dev/null +++ b/lib/export/irs/Makefile.in @@ -0,0 +1,86 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.4 2009-12-05 23:31:40 each Exp $ + +top_srcdir = @top_srcdir@ +srcdir = @top_srcdir@/lib/irs +export_srcdir = @top_srcdir@/lib/export + +@BIND9_VERSION@ + +@LIBIRS_API@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I. -I./include -I${srcdir}/include \ + ${ISCCFG_INCLUDES} -I../dns/include ${DNS_INCLUDES} \ + -I${export_srcdir}/isc/include ${ISC_INCLUDES} +CDEFINES = +CWARNINGS = + +# Alphabetically +OBJS = context.@O@ \ + dnsconf.@O@ \ + gai_strerror.@O@ getaddrinfo.@O@ getnameinfo.@O@ \ + resconf.@O@ + +# Alphabetically +SRCS = context.c \ + dnsconf.c \ + gai_sterror.c getaddrinfo.c getnameinfo.c \ + resconf.c + +ISCLIBS = ../isc/libisc.@A@ +DNSLIBS = ../dns/libdns.@A@ +ISCCFGLIBS = ../isccfg/libisccfg.@A@ + +LIBS = @LIBS@ + +SUBDIRS = include +TARGETS = timestamp + +@BIND9_MAKE_RULES@ + +version.@O@: ${srcdir}/version.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DVERSION=\"${VERSION}\" \ + -DLIBINTERFACE=${LIBINTERFACE} \ + -DLIBREVISION=${LIBREVISION} \ + -DLIBAGE=${LIBAGE} \ + -c ${srcdir}/version.c + +libirs.@SA@: ${OBJS} version.@O@ + ${AR} ${ARFLAGS} $@ ${OBJS} version.@O@ + ${RANLIB} $@ + +libirs.la: ${OBJS} version.@O@ + ${LIBTOOL_MODE_LINK} \ + ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libirs.la \ + -rpath ${export_libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} version.@O@ ${LIBS} ${ISCCFGLIBS} ${DNSLIBS} ${ISCLIBS} + +timestamp: libirs.@A@ + touch timestamp + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_libdir} + +install:: timestamp installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libirs.@A@ \ + ${DESTDIR}${export_libdir} + +clean distclean:: + rm -f libirs.@A@ libirs.la timestamp diff --git a/lib/export/irs/include/Makefile.in b/lib/export/irs/include/Makefile.in new file mode 100644 index 0000000..e6d4eae --- /dev/null +++ b/lib/export/irs/include/Makefile.in @@ -0,0 +1,24 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.2 2009-09-01 00:22:27 jinmei Exp $ + +srcdir = @srdir@ +top_srcdir = @top_srcdir@ + + +SUBDIRS = irs +TARGETS = + +@BIND9_MAKE_RULES@ diff --git a/lib/export/irs/include/irs/Makefile.in b/lib/export/irs/include/irs/Makefile.in new file mode 100644 index 0000000..93f4200 --- /dev/null +++ b/lib/export/irs/include/irs/Makefile.in @@ -0,0 +1,46 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ + +# +# Only list headers that are to be installed and are not +# machine generated. The latter are handled specially in the +# install target below. +# +HEADERS = context.h dnsconf.h resconf.h types.h version.h + +SUBDIRS = +TARGETS = + +@BIND9_MAKE_RULES@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_includedir}/irs + +install:: installdirs + for i in ${HEADERS}; do \ + ${INSTALL_DATA} ${top_srcdir}/lib/irs/include/irs/$$i \ + ${DESTDIR}${export_includedir}/irs ; \ + done + ${INSTALL_DATA} ${top_srcdir}/lib/irs/include/irs/netdb.h \ + ${DESTDIR}${export_includedir}/irs + ${INSTALL_DATA} ${top_srcdir}/lib/irs/include/irs/platform.h \ + ${DESTDIR}${export_includedir}/irs + +distclean:: + rm -f netdb.h platform.h diff --git a/lib/export/isc/Makefile.in b/lib/export/isc/Makefile.in new file mode 100644 index 0000000..fa1c367 --- /dev/null +++ b/lib/export/isc/Makefile.in @@ -0,0 +1,139 @@ +# Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.8 2010-06-09 23:50:58 tbox Exp $ + +top_srcdir = @top_srcdir@ +srcdir = @top_srcdir@/lib/isc +export_srcdir = @top_srcdir@/lib/export + +@BIND9_VERSION@ + +@LIBISC_API@ + +CINCLUDES = -I${srcdir}/unix/include \ + -I${srcdir}/@ISC_THREAD_DIR@/include \ + -I${srcdir}/@ISC_ARCH_DIR@/include \ + -I${export_srcdir}/isc/include -I${srcdir}/include \ + @ISC_OPENSSL_INC@ +CDEFINES = @USE_OPENSSL@ -DUSE_APPIMPREGISTER -DUSE_MEMIMPREGISTER \ + -DUSE_SOCKETIMPREGISTER -DUSE_TASKIMPREGISTER \ + -DUSE_TIMERIMPREGISTER +CWARNINGS = + +# Alphabetically +# {file,dir}.c is necessary for isclog +# symtab.c is necessary for isccfg +APIOBJS = app_api.@O@ mem_api.@O@ socket_api.@O@ \ + task_api.@O@ timer_api.@O@ + +ISCDRIVEROBJS = mem.@O@ unix/socket.@O@ task.@O@ timer.@O@ lib.@O@ \ + heap.@O@ #timer module depends on this + +UNIXOBJS = @ISC_ISCIPV6_O@ \ + unix/app.@O@ \ + unix/dir.@O@ \ + unix/errno2result.@O@ \ + unix/file.@O@ \ + unix/fsaccess.@O@ \ + unix/stdio.@O@ \ + unix/stdtime.@O@ unix/strerror.@O@ unix/time.@O@ + +NLSOBJS = nls/msgcat.@O@ + +THREADOPTOBJS = @ISC_THREAD_DIR@/condition.@O@ @ISC_THREAD_DIR@/mutex.@O@ + +THREADOBJS = @THREADOPTOBJS@ @ISC_THREAD_DIR@/thread.@O@ + +WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \ + win32/fsaccess.@O@ win32/once.@O@ win32/stdtime.@O@ \ + win32/thread.@O@ win32/time.@O@ + +# Alphabetically +OBJS = @ISC_EXTRA_OBJS@ \ + assertions.@O@ backtrace.@O@ backtrace-emptytbl.@O@ base32.@O@ \ + base64.@O@ buffer.@O@ bufferlist.@O@ \ + error.@O@ event.@O@ \ + hash.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \ + inet_aton.@O@ iterated_hash.@O@ lex.@O@ lfsr.@O@ log.@O@ \ + md5.@O@ mutexblock.@O@ \ + netaddr.@O@ netscope.@O@ \ + ondestroy.@O@ \ + parseint.@O@ portset.@O@ radix.@O@ \ + random.@O@ refcount.@O@ region.@O@ result.@O@ rwlock.@O@ \ + serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ stats.@O@ string.@O@ \ + symtab.@O@ \ + version.@O@ \ + ${APIOBJS} ${ISCDRIVEROBJS} \ + ${UNIXOBJS} ${NLSOBJS} ${THREADOBJS} + +# Alphabetically +APISRCS = app_api.c mem_api.c socket_api.c \ + task_api.c timer_api.c + +ISCDRIVERSRCS = mem.c task.c lib.c timer.c heap.c + +SRCS = @ISC_EXTRA_SRCS@ \ + assertions.c backtrace.c backtrace-emptytbl.c base32.c \ + base64.c buffer.c bufferlist.c \ + error.c event.c \ + hash.c hex.c hmacmd5.c hmacsha.c \ + inet_aton.c iterated_hash.c lex.c log.c lfsr.c \ + md5.c mutexblock.c \ + netaddr.c netscope.c \ + ondestroy.c \ + parseint.c portset.c radix.c \ + random.c refcount.c region.c result.c rwlock.c \ + serial.c sha1.c sha2.c sockaddr.c stats.c string.c symtab.c \ + version.c \ + ${APISRCS} ${ISCDRIVERSRCS} + +LIBS = @LIBS@ + +SUBDIRS = include unix nls @ISC_THREAD_DIR@ +TARGETS = timestamp + +@BIND9_MAKE_RULES@ + +version.@O@: ${srcdir}/version.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DVERSION=\"${VERSION}\" \ + -DLIBINTERFACE=${LIBINTERFACE} \ + -DLIBREVISION=${LIBREVISION} \ + -DLIBAGE=${LIBAGE} \ + -c ${srcdir}/version.c + +libisc.@SA@: ${OBJS} + ${AR} ${ARFLAGS} $@ ${OBJS} + ${RANLIB} $@ + +libisc.la: ${OBJS} + ${LIBTOOL_MODE_LINK} \ + ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc.la \ + -rpath ${export_libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${LIBS} + +timestamp: libisc.@A@ + touch timestamp + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_libdir} + +install:: timestamp installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libisc.@A@ \ + ${DESTDIR}${export_libdir} + +clean distclean:: + rm -f libisc.@A@ libisc.la timestamp diff --git a/lib/export/isc/include/Makefile.in b/lib/export/isc/include/Makefile.in new file mode 100644 index 0000000..f89628b --- /dev/null +++ b/lib/export/isc/include/Makefile.in @@ -0,0 +1,24 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.2 2009-09-01 00:22:27 jinmei Exp $ + +srcdir = @srdir@ +top_srcdir = @top_srcdir@ + + +SUBDIRS = isc +TARGETS = + +@BIND9_MAKE_RULES@ diff --git a/lib/export/isc/include/isc/Makefile.in b/lib/export/isc/include/isc/Makefile.in new file mode 100644 index 0000000..0336ba2 --- /dev/null +++ b/lib/export/isc/include/isc/Makefile.in @@ -0,0 +1,66 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.3 2009-12-05 23:31:41 each Exp $ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +export_srcdir = @top_srcdir@/lib/export + +@BIND9_VERSION@ + +# +# Only list headers that are to be installed and are not +# machine generated. The latter are handled specially in the +# install target below. +# +HEADERS = app.h assertions.h base64.h bitstring.h boolean.h \ + buffer.h bufferlist.h commandline.h entropy.h error.h event.h \ + eventclass.h file.h formatcheck.h fsaccess.h \ + hash.h heap.h hex.h hmacmd5.h \ + httpd.h \ + interfaceiter.h @ISC_IPV6_H@ iterated_hash.h lang.h lex.h \ + lfsr.h lib.h list.h log.h \ + magic.h md5.h mem.h msgcat.h msgs.h \ + mutexblock.h namespace.h netaddr.h ondestroy.h os.h parseint.h \ + print.h quota.h radix.h random.h ratelimiter.h \ + refcount.h region.h resource.h \ + result.h resultclass.h rwlock.h serial.h sha1.h sha2.h \ + sockaddr.h socket.h stdio.h stdlib.h string.h \ + symtab.h \ + task.h taskpool.h timer.h types.h util.h version.h \ + xml.h + +SUBDIRS = +TARGETS = + +@BIND9_MAKE_RULES@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_includedir}/isc + +install:: installdirs + for i in ${HEADERS}; do \ + ${INSTALL_DATA} ${top_srcdir}/lib/isc/include/isc/$$i \ + ${DESTDIR}${export_includedir}/isc ; \ + done + ${INSTALL_DATA} ${top_srcdir}/lib/isc/include/isc/platform.h \ + ${DESTDIR}${export_includedir}/isc + ${INSTALL_DATA} ${top_srcdir}/lib/isc/@ISC_ARCH_DIR@/include/isc/atomic.h \ + ${DESTDIR}${export_includedir}/isc + ${INSTALL_DATA} ${export_srcdir}/isc/include/isc/bind9.h \ + ${DESTDIR}${export_includedir}/isc + +distclean:: + rm -f platform.h diff --git a/lib/export/isc/include/isc/bind9.h b/lib/export/isc/include/isc/bind9.h new file mode 100644 index 0000000..380ca85 --- /dev/null +++ b/lib/export/isc/include/isc/bind9.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: bind9.h,v 1.2 2009-12-05 23:31:41 each Exp $ */ + +#ifndef ISC_BIND9_H +#define ISC_BIND9_H 1 + +/* + * This determines whether we are building BIND9 or using the exported + * libisc/libdns libraries. The version of this file included in the + * standard BIND9 build defines BIND9; the version included with the + * exportable libraries does not. + */ +#undef BIND9 + +#endif /* ISC_BIND9_H */ diff --git a/lib/export/isc/nls/Makefile.in b/lib/export/isc/nls/Makefile.in new file mode 100644 index 0000000..da2513f --- /dev/null +++ b/lib/export/isc/nls/Makefile.in @@ -0,0 +1,35 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ + +top_srcdir = @top_srcdir@ +srcdir = @top_srcdir@/lib/isc/nls + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I${srcdir}/unix/include \ + ${ISC_INCLUDES} + +CDEFINES = +CWARNINGS = + +OBJS = msgcat.@O@ + +SRCS = msgcat.c + +SUBDIRS = +TARGETS = ${OBJS} + +@BIND9_MAKE_RULES@ diff --git a/lib/export/isc/nothreads/Makefile.in b/lib/export/isc/nothreads/Makefile.in new file mode 100644 index 0000000..3bffb4e --- /dev/null +++ b/lib/export/isc/nothreads/Makefile.in @@ -0,0 +1,40 @@ +# Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.5 2010-06-09 23:50:58 tbox Exp $ + +top_srcdir = @top_srcdir@ +srcdir = @top_srcdir@/lib/isc/nothreads + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I${srcdir}/include \ + -I${srcdir}/../unix/include \ + -I../include \ + -I${srcdir}/../include \ + -I${srcdir}/.. + +CDEFINES = +CWARNINGS = + +THREADOPTOBJS = condition.@O@ mutex.@O@ +OBJS = @THREADOPTOBJS@ thread.@O@ + +THREADOPTSRCS = condition.c mutex.c +SRCS = @THREADOPTSRCS@ thread.c + +SUBDIRS = include +TARGETS = ${OBJS} + +@BIND9_MAKE_RULES@ diff --git a/lib/export/isc/nothreads/include/Makefile.in b/lib/export/isc/nothreads/include/Makefile.in new file mode 100644 index 0000000..f89628b --- /dev/null +++ b/lib/export/isc/nothreads/include/Makefile.in @@ -0,0 +1,24 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.2 2009-09-01 00:22:27 jinmei Exp $ + +srcdir = @srdir@ +top_srcdir = @top_srcdir@ + + +SUBDIRS = isc +TARGETS = + +@BIND9_MAKE_RULES@ diff --git a/lib/export/isc/nothreads/include/isc/Makefile.in b/lib/export/isc/nothreads/include/isc/Makefile.in new file mode 100644 index 0000000..423f10a --- /dev/null +++ b/lib/export/isc/nothreads/include/isc/Makefile.in @@ -0,0 +1,36 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.2 2009-09-01 00:22:27 jinmei Exp $ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_VERSION@ + +HEADERS = condition.h mutex.h once.h thread.h + +SUBDIRS = +TARGETS = + +@BIND9_MAKE_RULES@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_includedir}/isc + +install:: installdirs + for i in ${HEADERS}; do \ + ${INSTALL_DATA} $(top_srcdir)/lib/isc/nothreads/include/isc/$$i \ + ${DESTDIR}${export_includedir}/isc ; \ + done diff --git a/lib/export/isc/pthreads/Makefile.in b/lib/export/isc/pthreads/Makefile.in new file mode 100644 index 0000000..5fac018 --- /dev/null +++ b/lib/export/isc/pthreads/Makefile.in @@ -0,0 +1,38 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ + +top_srcdir = @top_srcdir@ +srcdir = @top_srcdir@/lib/isc/pthreads + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I${srcdir}/include \ + -I${srcdir}/../unix/include \ + -I../include \ + -I${srcdir}/../include \ + -I${srcdir}/.. + +CDEFINES = +CWARNINGS = + +OBJS = condition.@O@ mutex.@O@ thread.@O@ + +SRCS = condition.c mutex.c thread.c + +SUBDIRS = include +TARGETS = ${OBJS} + +@BIND9_MAKE_RULES@ diff --git a/lib/export/isc/pthreads/include/Makefile.in b/lib/export/isc/pthreads/include/Makefile.in new file mode 100644 index 0000000..f89628b --- /dev/null +++ b/lib/export/isc/pthreads/include/Makefile.in @@ -0,0 +1,24 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.2 2009-09-01 00:22:27 jinmei Exp $ + +srcdir = @srdir@ +top_srcdir = @top_srcdir@ + + +SUBDIRS = isc +TARGETS = + +@BIND9_MAKE_RULES@ diff --git a/lib/export/isc/pthreads/include/isc/Makefile.in b/lib/export/isc/pthreads/include/isc/Makefile.in new file mode 100644 index 0000000..807de94 --- /dev/null +++ b/lib/export/isc/pthreads/include/isc/Makefile.in @@ -0,0 +1,36 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.2 2009-09-01 00:22:27 jinmei Exp $ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_VERSION@ + +HEADERS = condition.h mutex.h once.h thread.h + +SUBDIRS = +TARGETS = + +@BIND9_MAKE_RULES@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_includedir}/isc + +install:: installdirs + for i in ${HEADERS}; do \ + ${INSTALL_DATA} $(top_srcdir)/lib/isc/pthreads/include/isc/$$i \ + ${DESTDIR}${export_includedir}/isc ; \ + done diff --git a/lib/export/isc/unix/Makefile.in b/lib/export/isc/unix/Makefile.in new file mode 100644 index 0000000..81746a4 --- /dev/null +++ b/lib/export/isc/unix/Makefile.in @@ -0,0 +1,57 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ + +top_srcdir = @top_srcdir@ +srcdir = @top_srcdir@/lib/isc/unix + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I${srcdir}/include \ + -I${srcdir}/../@ISC_THREAD_DIR@/include \ + -I../include \ + -I${srcdir}/../include \ + -I${srcdir}/.. + +CDEFINES = -DUSE_SOCKETIMPREGISTER -DUSE_APPIMPREGISTER + +CWARNINGS = + +# Alphabetically +ISCDRIVEROBJS = app.@O@ socket.@O@ + +OBJS = @ISC_IPV6_O@ \ + dir.@O@ \ + errno2result.@O@ \ + file.@O@ fsaccess.@O@ \ + stdio.@O@ stdtime.@O@ strerror.@O@ \ + time.@O@ \ + ${ISCDRIVEROBJS} + +# Alphabetically +ISCDRIVERSRCS = app.c socket.c + +SRCS = @ISC_IPV6_C@ \ + dir.c \ + errno2result.c \ + file.c fsaccess.c \ + stdio.c stdtime.c strerror.c \ + time.c \ + ${ISCDRIVERSRCS} + +SUBDIRS = include +TARGETS = ${OBJS} + +@BIND9_MAKE_RULES@ diff --git a/lib/export/isc/unix/include/Makefile.in b/lib/export/isc/unix/include/Makefile.in new file mode 100644 index 0000000..f89628b --- /dev/null +++ b/lib/export/isc/unix/include/Makefile.in @@ -0,0 +1,24 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.2 2009-09-01 00:22:27 jinmei Exp $ + +srcdir = @srdir@ +top_srcdir = @top_srcdir@ + + +SUBDIRS = isc +TARGETS = + +@BIND9_MAKE_RULES@ diff --git a/lib/export/isc/unix/include/isc/Makefile.in b/lib/export/isc/unix/include/isc/Makefile.in new file mode 100644 index 0000000..21ce049 --- /dev/null +++ b/lib/export/isc/unix/include/isc/Makefile.in @@ -0,0 +1,37 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.2 2009-09-01 00:22:27 jinmei Exp $ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_VERSION@ + +HEADERS = dir.h int.h net.h netdb.h offset.h stdtime.h \ + syslog.h time.h + +SUBDIRS = +TARGETS = + +@BIND9_MAKE_RULES@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_includedir}/isc + +install:: installdirs + for i in ${HEADERS}; do \ + ${INSTALL_DATA} $(top_srcdir)/lib/isc/unix/include/isc/$$i \ + ${DESTDIR}${export_includedir}/isc ; \ + done diff --git a/lib/export/isccfg/Makefile.in b/lib/export/isccfg/Makefile.in new file mode 100644 index 0000000..ed2b2cf --- /dev/null +++ b/lib/export/isccfg/Makefile.in @@ -0,0 +1,83 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.4 2009-12-05 23:31:41 each Exp $ + +top_srcdir = @top_srcdir@ +srcdir = @top_srcdir@/lib/isccfg +export_srcdir = @top_srcdir@/lib/export + +@BIND9_VERSION@ + +@LIBISCCFG_API@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I. ${DNS_INCLUDES} -I${export_srcdir}/isc/include \ + ${ISC_INCLUDES} ${ISCCFG_INCLUDES} + +CDEFINES = +CWARNINGS = + +ISCLIBS = ../isc/libisc.@A@ +DNSLIBS = ../dns/libdns.@A@ + +ISCDEPLIBS = ../../lib/isc/libisc.@A@ +ISCCFGDEPLIBS = libisccfg.@A@ + +LIBS = @LIBS@ + +SUBDIRS = include + +# Alphabetically +OBJS = dnsconf.@O@ log.@O@ parser.@O@ version.@O@ + +# Alphabetically +SRCS = dnsconf.c log.c parser.c version.c + +TARGETS = timestamp + +@BIND9_MAKE_RULES@ + +version.@O@: ${srcdir}/version.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DVERSION=\"${VERSION}\" \ + -DLIBINTERFACE=${LIBINTERFACE} \ + -DLIBREVISION=${LIBREVISION} \ + -DLIBAGE=${LIBAGE} \ + -c ${srcdir}/version.c + +libisccfg.@SA@: ${OBJS} + ${AR} ${ARFLAGS} $@ ${OBJS} + ${RANLIB} $@ + +libisccfg.la: ${OBJS} + ${LIBTOOL_MODE_LINK} \ + ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisccfg.la \ + -rpath ${export_libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${LIBS} ${DNSLIBS} ${ISCLIBS} + +timestamp: libisccfg.@A@ + touch timestamp + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_libdir} + +install:: timestamp installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libisccfg.@A@ \ + ${DESTDIR}${export_libdir} + +clean distclean:: + rm -f libisccfg.@A@ timestamp diff --git a/lib/export/isccfg/include/Makefile.in b/lib/export/isccfg/include/Makefile.in new file mode 100644 index 0000000..896c467 --- /dev/null +++ b/lib/export/isccfg/include/Makefile.in @@ -0,0 +1,24 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.2 2009-09-01 00:22:27 jinmei Exp $ + +srcdir = @srdir@ +top_srcdir = @top_srcdir@ + + +SUBDIRS = isccfg +TARGETS = + +@BIND9_MAKE_RULES@ diff --git a/lib/export/isccfg/include/isccfg/Makefile.in b/lib/export/isccfg/include/isccfg/Makefile.in new file mode 100644 index 0000000..3f97894 --- /dev/null +++ b/lib/export/isccfg/include/isccfg/Makefile.in @@ -0,0 +1,42 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_VERSION@ + +# +# Only list headers that are to be installed and are not +# machine generated. The latter are handled specially in the +# install target below. +# +HEADERS = cfg.h grammar.h log.h dnsconf.h version.h + +SUBDIRS = +TARGETS = + +@BIND9_MAKE_RULES@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs \ + ${DESTDIR}${export_includedir}/isccfg + +install:: installdirs + for i in ${HEADERS}; do \ + ${INSTALL_DATA} ${top_srcdir}/lib/isccfg/include/isccfg/$$i \ + ${DESTDIR}${export_includedir}/isccfg ; \ + done diff --git a/lib/export/samples/Makefile-postinstall.in b/lib/export/samples/Makefile-postinstall.in new file mode 100644 index 0000000..10a26f4 --- /dev/null +++ b/lib/export/samples/Makefile-postinstall.in @@ -0,0 +1,78 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile-postinstall.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ + +srcdir = @srcdir@ +#prefix = @prefix@ +#exec_prefix = @exec_prefix@ + +CDEFINES = +CWARNINGS = + +DNSLIBS = -ldns @DNS_CRYPTO_LIBS@ +ISCLIBS = -lisc +ISCCFGLIBS = -lisccfg +IRSLIBS = -lirs + +LIBS = ${DNSLIBS} ${ISCCFGLIBS} ${ISCLIBS} @LIBS@ + +SUBDIRS = + +TARGETS = sample@EXEEXT@ sample-async@EXEEXT@ sample-gai@EXEEXT@ \ + sample-update@EXEEXT@ sample-request@EXEEXT@ nsprobe@EXEEXT@ \ + dlvchecks@EXEEXT@ + +OBJS = sample.@O@ sample-async.@O@ sample-gai.@O@ sample-update.@O@ \ + sample-request.@O@ nsprobe.@O@ dlvchecks.@O@ + +SRCS = sample.c sample-async.c sample-gai.c sample-update.c \ + sample-request.c nsprobe.c dlvchecks..c + +@BIND9_MAKE_RULES@ + +# The following two may depend on BIND9_MAKE_RULES +CINCLUDES = -I@export_includedir@ +LDFLAGS = -L@export_libdir@ + +sample@EXEEXT@: sample.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + sample.@O@ ${LIBS} + +sample-async@EXEEXT@: sample-async.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + sample-async.@O@ ${LIBS} + +sample-gai@EXEEXT@: sample-gai.@O@ ${IRSDEPLIBS} ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + sample-gai.@O@ ${IRSLIBS} ${LIBS} + +sample-update@EXEEXT@: sample-update.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + sample-update.@O@ ${LIBS} + +sample-request@EXEEXT@: sample-request.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + sample-request.@O@ ${LIBS} + +nsprobe@EXEEXT@: nsprobe.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + nsprobe.@O@ ${LIBS} + +dlvchecks@EXEEXT@: dlvchecks.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + dlvchecks.@O@ ${LIBS} + +clean distclean maintainer-clean:: + rm -f ${TARGETS} diff --git a/lib/export/samples/Makefile.in b/lib/export/samples/Makefile.in new file mode 100644 index 0000000..ff8e916 --- /dev/null +++ b/lib/export/samples/Makefile.in @@ -0,0 +1,98 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.4 2009-12-05 23:31:41 each Exp $ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +export_srcdir = @top_srcdir@/lib/export + +@BIND9_VERSION@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I${srcdir}/include -I../dns/include \ + -I${export_srcdir}/isc/include \ + ${DNS_INCLUDES} ${ISC_INCLUDES} \ + -I${top_srcdir}/lib/irs/include + +CDEFINES = +CWARNINGS = + +DNSLIBS = ../dns/libdns.@A@ @DNS_CRYPTO_LIBS@ +ISCLIBS = ../isc/libisc.@A@ +ISCCFGLIBS = ../isccfg/libisccfg.@A@ +IRSLIBS = ../irs/libirs.@A@ + +DNSDEPLIBS = ../dns/libdns.@A@ +ISCDEPLIBS = ../isc/libisc.@A@ +ISCCFGDEPLIBS = ../isccfg/libisccfg.@A@ +IRSDEPLIBS = ../irs/libirs.@A@ + +DEPLIBS = ${DNSDEPLIBS} ${ISCCFGDEPLIBS} ${ISCDEPLIBS} + +LIBS = ${DNSLIBS} ${ISCCFGLIBS} ${ISCLIBS} @LIBS@ + +SUBDIRS = + +TARGETS = sample@EXEEXT@ sample-async@EXEEXT@ sample-gai@EXEEXT@ \ + sample-update@EXEEXT@ sample-request@EXEEXT@ nsprobe@EXEEXT@ + +OBJS = sample.@O@ sample-async.@O@ sample-gai.@O@ sample-update.@O@ \ + sample-request.@O@ nsprobe.@O@ + +UOBJS = + +SRCS = sample.c sample-async.c sample-gai.c sample-update.c \ + sample-request.c nsprobe.c + +MANPAGES = + +HTMLPAGES = + +MANOBJS = ${MANPAGES} ${HTMLPAGES} + +@BIND9_MAKE_RULES@ + +sample@EXEEXT@: sample.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + sample.@O@ ${LIBS} + +sample-async@EXEEXT@: sample-async.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + sample-async.@O@ ${LIBS} + +sample-gai@EXEEXT@: sample-gai.@O@ ${IRSDEPLIBS} ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + sample-gai.@O@ ${IRSLIBS} ${LIBS} + +sample-update@EXEEXT@: sample-update.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + sample-update.@O@ ${LIBS} + +sample-request@EXEEXT@: sample-request.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + sample-request.@O@ ${LIBS} + +nsprobe@EXEEXT@: nsprobe.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + nsprobe.@O@ ${LIBS} + +doc man:: ${MANOBJS} + +docclean manclean maintainer-clean:: + rm -f ${MANOBJS} + +clean distclean maintainer-clean:: + rm -f ${TARGETS} diff --git a/lib/export/samples/nsprobe.c b/lib/export/samples/nsprobe.c new file mode 100644 index 0000000..85c572d --- /dev/null +++ b/lib/export/samples/nsprobe.c @@ -0,0 +1,1220 @@ +/* + * Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: nsprobe.c,v 1.7 2010-01-07 23:48:54 tbox Exp $ */ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PROBES 1000 + +static dns_client_t *client = NULL; +static isc_task_t *probe_task = NULL; +static isc_appctx_t *actx = NULL; +static isc_mem_t *mctx = NULL; +static unsigned int outstanding_probes = 0; +const char *cacheserver = "127.0.0.1"; +static FILE *fp; + +typedef enum { + none, + exist, + nxdomain, + othererr, + multiplesoa, + multiplecname, + brokenanswer, + lame, + timedout, + notype, + unexpected +} query_result_t; + +struct server { + ISC_LINK(struct server) link; + + isc_sockaddr_t address; + query_result_t result_a; + query_result_t result_aaaa; +}; + +struct probe_ns { + ISC_LINK(struct probe_ns) link; + + dns_fixedname_t fixedname; + dns_name_t *name; + struct server *current_server; + ISC_LIST(struct server) servers; +}; + +struct probe_trans { + isc_boolean_t inuse; + char *domain; + dns_fixedname_t fixedname; + dns_name_t *qname; + const char **qlabel; + isc_boolean_t qname_found; + dns_clientrestrans_t *resid; + dns_message_t *qmessage; + dns_message_t *rmessage; + dns_clientreqtrans_t *reqid; + + /* NS list */ + struct probe_ns *current_ns; + ISC_LIST(struct probe_ns) nslist; +}; + +struct lcl_stat { + unsigned long valid; + unsigned long ignore; + unsigned long nxdomain; + unsigned long othererr; + unsigned long multiplesoa; + unsigned long multiplecname; + unsigned long brokenanswer; + unsigned long lame; + unsigned long unknown; +} server_stat, domain_stat; + +static unsigned long number_of_domains = 0; +static unsigned long number_of_servers = 0; +static unsigned long multiple_error_domains = 0; +static isc_boolean_t debug_mode = ISC_FALSE; +static int verbose_level = 0; +static const char *qlabels[] = {"www.", "ftp.", NULL}; +static struct probe_trans probes[MAX_PROBES]; + +static isc_result_t probe_domain(struct probe_trans *trans); +static void reset_probe(struct probe_trans *trans); +static isc_result_t fetch_nsaddress(struct probe_trans *trans); +static isc_result_t probe_name(struct probe_trans *trans, + dns_rdatatype_t type); + +/* Dump an rdataset for debug */ +static isc_result_t +print_rdataset(dns_rdataset_t *rdataset, dns_name_t *owner) { + isc_buffer_t target; + isc_result_t result; + isc_region_t r; + char t[4096]; + + if (!debug_mode) + return (ISC_R_SUCCESS); + + isc_buffer_init(&target, t, sizeof(t)); + + if (!dns_rdataset_isassociated(rdataset)) + return (ISC_R_SUCCESS); + result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE, + &target); + if (result != ISC_R_SUCCESS) + return (result); + isc_buffer_usedregion(&target, &r); + printf("%.*s", (int)r.length, (char *)r.base); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +print_name(dns_name_t *name) { + isc_result_t result; + isc_buffer_t target; + isc_region_t r; + char t[4096]; + + isc_buffer_init(&target, t, sizeof(t)); + result = dns_name_totext(name, ISC_TRUE, &target); + if (result == ISC_R_SUCCESS) { + isc_buffer_usedregion(&target, &r); + printf("%.*s", (int)r.length, (char *)r.base); + } else + printf("(invalid name)"); + + return (result); +} + +static isc_result_t +print_address(FILE *fp, isc_sockaddr_t *addr) { + char buf[NI_MAXHOST]; + + if (getnameinfo(&addr->type.sa, addr->length, buf, sizeof(buf), + NULL, 0, NI_NUMERICHOST) == 0) { + fprintf(fp, "%s", buf); + } else { + fprintf(fp, "(invalid address)"); + } + + return (ISC_R_SUCCESS); +} + +static void +ctxs_destroy(isc_mem_t **mctxp, isc_appctx_t **actxp, + isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp, + isc_timermgr_t **timermgrp) +{ + if (*taskmgrp != NULL) + isc_taskmgr_destroy(taskmgrp); + + if (*timermgrp != NULL) + isc_timermgr_destroy(timermgrp); + + if (*socketmgrp != NULL) + isc_socketmgr_destroy(socketmgrp); + + if (*actxp != NULL) + isc_appctx_destroy(actxp); + + if (*mctxp != NULL) + isc_mem_destroy(mctxp); +} + +static isc_result_t +ctxs_init(isc_mem_t **mctxp, isc_appctx_t **actxp, + isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp, + isc_timermgr_t **timermgrp) +{ + isc_result_t result; + + result = isc_mem_create(0, 0, mctxp); + if (result != ISC_R_SUCCESS) + goto fail; + + result = isc_appctx_create(*mctxp, actxp); + if (result != ISC_R_SUCCESS) + goto fail; + + result = isc_taskmgr_createinctx(*mctxp, *actxp, 1, 0, taskmgrp); + if (result != ISC_R_SUCCESS) + goto fail; + + result = isc_socketmgr_createinctx(*mctxp, *actxp, socketmgrp); + if (result != ISC_R_SUCCESS) + goto fail; + + result = isc_timermgr_createinctx(*mctxp, *actxp, timermgrp); + if (result != ISC_R_SUCCESS) + goto fail; + + return (ISC_R_SUCCESS); + + fail: + ctxs_destroy(mctxp, actxp, taskmgrp, socketmgrp, timermgrp); + + return (result); +} + +/* + * Common routine to make query data + */ +static isc_result_t +make_querymessage(dns_message_t *message, dns_name_t *qname0, + dns_rdatatype_t rdtype) +{ + dns_name_t *qname = NULL; + dns_rdataset_t *qrdataset = NULL; + isc_result_t result; + + message->opcode = dns_opcode_query; + message->rdclass = dns_rdataclass_in; + + result = dns_message_gettempname(message, &qname); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dns_message_gettemprdataset(message, &qrdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + + dns_name_init(qname, NULL); + dns_name_clone(qname0, qname); + dns_rdataset_init(qrdataset); + dns_rdataset_makequestion(qrdataset, message->rdclass, rdtype); + ISC_LIST_APPEND(qname->list, qrdataset, link); + dns_message_addname(message, qname, DNS_SECTION_QUESTION); + + return (ISC_R_SUCCESS); + + cleanup: + if (qname != NULL) + dns_message_puttempname(message, &qname); + if (qrdataset != NULL) + dns_message_puttemprdataset(message, &qrdataset); + if (message != NULL) + dns_message_destroy(&message); + return (result); +} + +/* + * Update statistics + */ +static inline void +increment_entry(unsigned long *entryp) { + (*entryp)++; + INSIST(*entryp != 0); /* check overflow */ +} + +static void +update_stat(struct probe_trans *trans) { + struct probe_ns *pns; + struct server *server; + struct lcl_stat local_stat; + unsigned int err_count = 0; + const char *stattype; + + increment_entry(&number_of_domains); + memset(&local_stat, 0, sizeof(local_stat)); + + /* Update per sever statistics */ + for (pns = ISC_LIST_HEAD(trans->nslist); pns != NULL; + pns = ISC_LIST_NEXT(pns, link)) { + for (server = ISC_LIST_HEAD(pns->servers); server != NULL; + server = ISC_LIST_NEXT(server, link)) { + increment_entry(&number_of_servers); + + if (server->result_aaaa == exist || + server->result_aaaa == notype) { + /* + * Don't care about the result of A query if + * the answer to AAAA query was expected. + */ + stattype = "valid"; + increment_entry(&server_stat.valid); + increment_entry(&local_stat.valid); + } else if (server->result_a == exist) { + switch (server->result_aaaa) { + case exist: + case notype: + stattype = "valid"; + increment_entry(&server_stat.valid); + increment_entry(&local_stat.valid); + break; + case timedout: + stattype = "ignore"; + increment_entry(&server_stat.ignore); + increment_entry(&local_stat.ignore); + break; + case nxdomain: + stattype = "nxdomain"; + increment_entry(&server_stat.nxdomain); + increment_entry(&local_stat.nxdomain); + break; + case othererr: + stattype = "othererr"; + increment_entry(&server_stat.othererr); + increment_entry(&local_stat.othererr); + break; + case multiplesoa: + stattype = "multiplesoa"; + increment_entry(&server_stat.multiplesoa); + increment_entry(&local_stat.multiplesoa); + break; + case multiplecname: + stattype = "multiplecname"; + increment_entry(&server_stat.multiplecname); + increment_entry(&local_stat.multiplecname); + break; + case brokenanswer: + stattype = "brokenanswer"; + increment_entry(&server_stat.brokenanswer); + increment_entry(&local_stat.brokenanswer); + break; + case lame: + stattype = "lame"; + increment_entry(&server_stat.lame); + increment_entry(&local_stat.lame); + break; + default: + stattype = "unknown"; + increment_entry(&server_stat.unknown); + increment_entry(&local_stat.unknown); + break; + } + } else { + stattype = "unknown"; + increment_entry(&server_stat.unknown); + increment_entry(&local_stat.unknown); + } + + if (verbose_level > 1 || + (verbose_level == 1 && + strcmp(stattype, "valid") != 0 && + strcmp(stattype, "unknown") != 0)) { + print_name(pns->name); + putchar('('); + print_address(stdout, &server->address); + printf(") for %s:%s\n", trans->domain, + stattype); + } + } + } + + /* Update per domain statistics */ + if (local_stat.ignore > 0) { + if (verbose_level > 0) + printf("%s:ignore\n", trans->domain); + increment_entry(&domain_stat.ignore); + err_count++; + } + if (local_stat.nxdomain > 0) { + if (verbose_level > 0) + printf("%s:nxdomain\n", trans->domain); + increment_entry(&domain_stat.nxdomain); + err_count++; + } + if (local_stat.othererr > 0) { + if (verbose_level > 0) + printf("%s:othererr\n", trans->domain); + increment_entry(&domain_stat.othererr); + err_count++; + } + if (local_stat.multiplesoa > 0) { + if (verbose_level > 0) + printf("%s:multiplesoa\n", trans->domain); + increment_entry(&domain_stat.multiplesoa); + err_count++; + } + if (local_stat.multiplecname > 0) { + if (verbose_level > 0) + printf("%s:multiplecname\n", trans->domain); + increment_entry(&domain_stat.multiplecname); + err_count++; + } + if (local_stat.brokenanswer > 0) { + if (verbose_level > 0) + printf("%s:brokenanswer\n", trans->domain); + increment_entry(&domain_stat.brokenanswer); + err_count++; + } + if (local_stat.lame > 0) { + if (verbose_level > 0) + printf("%s:lame\n", trans->domain); + increment_entry(&domain_stat.lame); + err_count++; + } + + if (err_count > 1) + increment_entry(&multiple_error_domains); + + /* + * We regard the domain as valid if and only if no authoritative server + * has a problem and at least one server is known to be valid. + */ + if (local_stat.valid > 0 && err_count == 0) { + if (verbose_level > 1) + printf("%s:valid\n", trans->domain); + increment_entry(&domain_stat.valid); + } + + /* + * If the domain has no available server or all servers have the + * 'unknown' result, the domain's result is also regarded as unknown. + */ + if (local_stat.valid == 0 && err_count == 0) { + if (verbose_level > 1) + printf("%s:unknown\n", trans->domain); + increment_entry(&domain_stat.unknown); + } +} + +/* + * Search for an existent name with an A RR + */ + +static isc_result_t +set_nextqname(struct probe_trans *trans) { + isc_result_t result; + size_t domainlen; + isc_buffer_t b; + char buf[4096]; /* XXX ad-hoc constant, but should be enough */ + + if (*trans->qlabel == NULL) + return (ISC_R_NOMORE); + + result = isc_string_copy(buf, sizeof(buf), *trans->qlabel); + if (result != ISC_R_SUCCESS) + return (result); + result = isc_string_append(buf, sizeof(buf), trans->domain); + if (result != ISC_R_SUCCESS) + return (result); + + domainlen = strlen(buf); + isc_buffer_init(&b, buf, domainlen); + isc_buffer_add(&b, domainlen); + dns_fixedname_init(&trans->fixedname); + trans->qname = dns_fixedname_name(&trans->fixedname); + result = dns_name_fromtext(trans->qname, &b, dns_rootname, + 0, NULL); + + trans->qlabel++; + + return (result); +} + +static void +request_done(isc_task_t *task, isc_event_t *event) { + struct probe_trans *trans = event->ev_arg; + dns_clientreqevent_t *rev = (dns_clientreqevent_t *)event; + dns_message_t *rmessage; + struct probe_ns *pns; + struct server *server; + isc_result_t result; + query_result_t *resultp; + dns_name_t *name; + dns_rdataset_t *rdataset; + dns_rdatatype_t type; + + REQUIRE(task == probe_task); + REQUIRE(trans != NULL && trans->inuse == ISC_TRUE); + rmessage = rev->rmessage; + REQUIRE(rmessage == trans->rmessage); + INSIST(outstanding_probes > 0); + + server = trans->current_ns->current_server; + INSIST(server != NULL); + + if (server->result_a == none) { + type = dns_rdatatype_a; + resultp = &server->result_a; + } else { + resultp = &server->result_aaaa; + type = dns_rdatatype_aaaa; + } + + if (rev->result == ISC_R_SUCCESS) { + if ((rmessage->flags & DNS_MESSAGEFLAG_AA) == 0) + *resultp = lame; + else if (rmessage->rcode == dns_rcode_nxdomain) + *resultp = nxdomain; + else if (rmessage->rcode != dns_rcode_noerror) + *resultp = othererr; + else if (rmessage->counts[DNS_SECTION_ANSWER] == 0) { + /* no error but empty answer */ + *resultp = notype; + } else { + result = dns_message_firstname(rmessage, + DNS_SECTION_ANSWER); + while (result == ISC_R_SUCCESS) { + name = NULL; + dns_message_currentname(rmessage, + DNS_SECTION_ANSWER, + &name); + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, + link)) { + (void)print_rdataset(rdataset, name); + + if (rdataset->type == + dns_rdatatype_cname || + rdataset->type == + dns_rdatatype_dname) { + /* Should chase the chain? */ + *resultp = exist; + goto found; + } else if (rdataset->type == type) { + *resultp = exist; + goto found; + } + } + result = dns_message_nextname(rmessage, + DNS_SECTION_ANSWER); + } + + /* + * Something unexpected happened: the response + * contained a non-empty authoritative answer, but we + * could not find an expected result. + */ + *resultp = unexpected; + } + } else if (rev->result == DNS_R_RECOVERABLE || + rev->result == DNS_R_BADLABELTYPE) { + /* Broken response. Try identifying known cases. */ + *resultp = brokenanswer; + + if (rmessage->counts[DNS_SECTION_ANSWER] > 0) { + result = dns_message_firstname(rmessage, + DNS_SECTION_ANSWER); + while (result == ISC_R_SUCCESS) { + /* + * Check to see if the response has multiple + * CNAME RRs. Update the result code if so. + */ + name = NULL; + dns_message_currentname(rmessage, + DNS_SECTION_ANSWER, + &name); + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, + link)) { + if (rdataset->type == + dns_rdatatype_cname && + dns_rdataset_count(rdataset) > 1) { + *resultp = multiplecname; + goto found; + } + } + result = dns_message_nextname(rmessage, + DNS_SECTION_ANSWER); + } + } + + if (rmessage->counts[DNS_SECTION_AUTHORITY] > 0) { + result = dns_message_firstname(rmessage, + DNS_SECTION_AUTHORITY); + while (result == ISC_R_SUCCESS) { + /* + * Check to see if the response has multiple + * SOA RRs. Update the result code if so. + */ + name = NULL; + dns_message_currentname(rmessage, + DNS_SECTION_AUTHORITY, + &name); + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, + link)) { + if (rdataset->type == + dns_rdatatype_soa && + dns_rdataset_count(rdataset) > 1) { + *resultp = multiplesoa; + goto found; + } + } + result = dns_message_nextname(rmessage, + DNS_SECTION_AUTHORITY); + } + } + } else if (rev->result == ISC_R_TIMEDOUT) + *resultp = timedout; + else { + fprintf(stderr, "unexpected result: %d (domain=%s, server=", + rev->result, trans->domain); + print_address(stderr, &server->address); + fputc('\n', stderr); + *resultp = unexpected; + } + + found: + INSIST(*resultp != none); + if (type == dns_rdatatype_a && *resultp == exist) + trans->qname_found = ISC_TRUE; + + dns_client_destroyreqtrans(&trans->reqid); + isc_event_free(&event); + dns_message_reset(trans->rmessage, DNS_MESSAGE_INTENTPARSE); + + result = probe_name(trans, type); + if (result == ISC_R_NOMORE) { + /* We've tried all addresses of all servers. */ + if (type == dns_rdatatype_a && trans->qname_found) { + /* + * If we've explored A RRs and found an existent + * record, we can move to AAAA. + */ + trans->current_ns = ISC_LIST_HEAD(trans->nslist); + probe_name(trans, dns_rdatatype_aaaa); + result = ISC_R_SUCCESS; + } else if (type == dns_rdatatype_a) { + /* + * No server provided an existent A RR of this name. + * Try next label. + */ + dns_fixedname_invalidate(&trans->fixedname); + trans->qname = NULL; + result = set_nextqname(trans); + if (result == ISC_R_SUCCESS) { + trans->current_ns = + ISC_LIST_HEAD(trans->nslist); + for (pns = trans->current_ns; pns != NULL; + pns = ISC_LIST_NEXT(pns, link)) { + for (server = ISC_LIST_HEAD(pns->servers); + server != NULL; + server = ISC_LIST_NEXT(server, + link)) { + INSIST(server->result_aaaa == + none); + server->result_a = none; + } + } + result = probe_name(trans, dns_rdatatype_a); + } + } + if (result != ISC_R_SUCCESS) { + /* + * We've explored AAAA RRs or failed to find a valid + * query label. Wrap up the result and move to the + * next domain. + */ + reset_probe(trans); + } + } else if (result != ISC_R_SUCCESS) + reset_probe(trans); /* XXX */ +} + +static isc_result_t +probe_name(struct probe_trans *trans, dns_rdatatype_t type) { + isc_result_t result; + struct probe_ns *pns; + struct server *server; + + REQUIRE(trans->reqid == NULL); + REQUIRE(type == dns_rdatatype_a || type == dns_rdatatype_aaaa); + + for (pns = trans->current_ns; pns != NULL; + pns = ISC_LIST_NEXT(pns, link)) { + for (server = ISC_LIST_HEAD(pns->servers); server != NULL; + server = ISC_LIST_NEXT(server, link)) { + if ((type == dns_rdatatype_a && + server->result_a == none) || + (type == dns_rdatatype_aaaa && + server->result_aaaa == none)) { + pns->current_server = server; + goto found; + } + } + } + + found: + trans->current_ns = pns; + if (pns == NULL) + return (ISC_R_NOMORE); + + INSIST(pns->current_server != NULL); + dns_message_reset(trans->qmessage, DNS_MESSAGE_INTENTRENDER); + result = make_querymessage(trans->qmessage, trans->qname, type); + if (result != ISC_R_SUCCESS) + return (result); + result = dns_client_startrequest(client, trans->qmessage, + trans->rmessage, + &pns->current_server->address, + 0, DNS_MESSAGEPARSE_BESTEFFORT, + NULL, 120, 0, 4, + probe_task, request_done, trans, + &trans->reqid); + + return (result); +} + +/* + * Get IP addresses of NSes + */ + +static void +resolve_nsaddress(isc_task_t *task, isc_event_t *event) { + struct probe_trans *trans = event->ev_arg; + dns_clientresevent_t *rev = (dns_clientresevent_t *)event; + dns_name_t *name; + dns_rdataset_t *rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + struct probe_ns *pns = trans->current_ns; + isc_result_t result; + + REQUIRE(task == probe_task); + REQUIRE(trans->inuse == ISC_TRUE); + REQUIRE(pns != NULL); + INSIST(outstanding_probes > 0); + + for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; + name = ISC_LIST_NEXT(name, link)) { + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + (void)print_rdataset(rdataset, name); + + if (rdataset->type != dns_rdatatype_a) + continue; + + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + dns_rdata_in_a_t rdata_a; + struct server *server; + + dns_rdataset_current(rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &rdata_a, + NULL); + if (result != ISC_R_SUCCESS) + continue; + + server = isc_mem_get(mctx, sizeof(*server)); + if (server == NULL) { + fprintf(stderr, "resolve_nsaddress: " + "mem_get failed"); + result = ISC_R_NOMEMORY; + goto cleanup; + } + isc_sockaddr_fromin(&server->address, + &rdata_a.in_addr, 53); + ISC_LINK_INIT(server, link); + server->result_a = none; + server->result_aaaa = none; + ISC_LIST_APPEND(pns->servers, server, link); + } + } + } + + cleanup: + dns_client_freeresanswer(client, &rev->answerlist); + dns_client_destroyrestrans(&trans->resid); + isc_event_free(&event); + + next_ns: + trans->current_ns = ISC_LIST_NEXT(pns, link); + if (trans->current_ns == NULL) { + trans->current_ns = ISC_LIST_HEAD(trans->nslist); + dns_fixedname_invalidate(&trans->fixedname); + trans->qname = NULL; + result = set_nextqname(trans); + if (result == ISC_R_SUCCESS) + result = probe_name(trans, dns_rdatatype_a); + } else { + result = fetch_nsaddress(trans); + if (result != ISC_R_SUCCESS) + goto next_ns; /* XXX: this is unlikely to succeed */ + } + + if (result != ISC_R_SUCCESS) + reset_probe(trans); +} + +static isc_result_t +fetch_nsaddress(struct probe_trans *trans) { + struct probe_ns *pns; + + pns = trans->current_ns; + REQUIRE(pns != NULL); + + return (dns_client_startresolve(client, pns->name, dns_rdataclass_in, + dns_rdatatype_a, 0, probe_task, + resolve_nsaddress, trans, + &trans->resid)); +} + +/* + * Get NS RRset for a given domain + */ + +static void +reset_probe(struct probe_trans *trans) { + struct probe_ns *pns; + struct server *server; + isc_result_t result; + + REQUIRE(trans->resid == NULL); + REQUIRE(trans->reqid == NULL); + + update_stat(trans); + + dns_message_reset(trans->qmessage, DNS_MESSAGE_INTENTRENDER); + dns_message_reset(trans->rmessage, DNS_MESSAGE_INTENTPARSE); + + trans->inuse = ISC_FALSE; + if (trans->domain != NULL) + isc_mem_free(mctx, trans->domain); + trans->domain = NULL; + if (trans->qname != NULL) + dns_fixedname_invalidate(&trans->fixedname); + trans->qname = NULL; + trans->qlabel = qlabels; + trans->qname_found = ISC_FALSE; + trans->current_ns = NULL; + + while ((pns = ISC_LIST_HEAD(trans->nslist)) != NULL) { + ISC_LIST_UNLINK(trans->nslist, pns, link); + while ((server = ISC_LIST_HEAD(pns->servers)) != NULL) { + ISC_LIST_UNLINK(pns->servers, server, link); + isc_mem_put(mctx, server, sizeof(*server)); + } + isc_mem_put(mctx, pns, sizeof(*pns)); + } + + outstanding_probes--; + + result = probe_domain(trans); + if (result == ISC_R_NOMORE && outstanding_probes == 0) + isc_app_ctxshutdown(actx); +} + +static void +resolve_ns(isc_task_t *task, isc_event_t *event) { + struct probe_trans *trans = event->ev_arg; + dns_clientresevent_t *rev = (dns_clientresevent_t *)event; + dns_name_t *name; + dns_rdataset_t *rdataset; + isc_result_t result = ISC_R_SUCCESS; + dns_rdata_t rdata = DNS_RDATA_INIT; + struct probe_ns *pns; + + REQUIRE(task == probe_task); + REQUIRE(trans->inuse == ISC_TRUE); + INSIST(outstanding_probes > 0); + + for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; + name = ISC_LIST_NEXT(name, link)) { + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + (void)print_rdataset(rdataset, name); + + if (rdataset->type != dns_rdatatype_ns) + continue; + + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + dns_rdata_ns_t ns; + + dns_rdataset_current(rdataset, &rdata); + /* + * Extract the name from the NS record. + */ + result = dns_rdata_tostruct(&rdata, &ns, NULL); + if (result != ISC_R_SUCCESS) + continue; + + pns = isc_mem_get(mctx, sizeof(*pns)); + if (pns == NULL) { + fprintf(stderr, + "resolve_ns: mem_get failed"); + result = ISC_R_NOMEMORY; + /* + * XXX: should we continue with the + * available servers anyway? + */ + goto cleanup; + } + + dns_fixedname_init(&pns->fixedname); + pns->name = + dns_fixedname_name(&pns->fixedname); + ISC_LINK_INIT(pns, link); + ISC_LIST_APPEND(trans->nslist, pns, link); + ISC_LIST_INIT(pns->servers); + + dns_name_copy(&ns.name, pns->name, NULL); + dns_rdata_reset(&rdata); + dns_rdata_freestruct(&ns); + } + } + } + + cleanup: + dns_client_freeresanswer(client, &rev->answerlist); + dns_client_destroyrestrans(&trans->resid); + isc_event_free(&event); + + if (!ISC_LIST_EMPTY(trans->nslist)) { + /* Go get addresses of NSes */ + trans->current_ns = ISC_LIST_HEAD(trans->nslist); + result = fetch_nsaddress(trans); + } else + result = ISC_R_FAILURE; + + if (result == ISC_R_SUCCESS) + return; + + reset_probe(trans); +} + +static isc_result_t +probe_domain(struct probe_trans *trans) { + isc_result_t result; + size_t domainlen; + isc_buffer_t b; + char buf[4096]; /* XXX ad hoc constant, but should be enough */ + char *cp; + + REQUIRE(trans != NULL); + REQUIRE(trans->inuse == ISC_FALSE); + REQUIRE(outstanding_probes < MAX_PROBES); + + /* Construct domain */ + cp = fgets(buf, sizeof(buf), fp); + if (cp == NULL) + return (ISC_R_NOMORE); + if ((cp = strchr(buf, '\n')) != NULL) /* zap NL if any */ + *cp = '\0'; + trans->domain = isc_mem_strdup(mctx, buf); + if (trans->domain == NULL) { + fprintf(stderr, + "failed to allocate memory for domain: %s", cp); + return (ISC_R_NOMEMORY); + } + + /* Start getting NS for the domain */ + domainlen = strlen(buf); + isc_buffer_init(&b, buf, domainlen); + isc_buffer_add(&b, domainlen); + dns_fixedname_init(&trans->fixedname); + trans->qname = dns_fixedname_name(&trans->fixedname); + result = dns_name_fromtext(trans->qname, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_client_startresolve(client, trans->qname, + dns_rdataclass_in, dns_rdatatype_ns, + 0, probe_task, resolve_ns, trans, + &trans->resid); + if (result != ISC_R_SUCCESS) + goto cleanup; + + trans->inuse = ISC_TRUE; + outstanding_probes++; + + return (ISC_R_SUCCESS); + + cleanup: + isc_mem_free(mctx, trans->domain); + dns_fixedname_invalidate(&trans->fixedname); + + return (result); +} + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "usage: nsprobe [-d] [-v [-v...]] [-c cache_address] " + "[input_file]\n"); + + exit(1); +} + +int +main(int argc, char *argv[]) { + int i, ch, error; + struct addrinfo hints, *res; + isc_result_t result; + isc_sockaddr_t sa; + isc_sockaddrlist_t servers; + isc_taskmgr_t *taskmgr = NULL; + isc_socketmgr_t *socketmgr = NULL; + isc_timermgr_t *timermgr = NULL; + + while ((ch = getopt(argc, argv, "c:dhv")) != -1) { + switch (ch) { + case 'c': + cacheserver = optarg; + break; + case 'd': + debug_mode = ISC_TRUE; + break; + case 'h': + usage(); + break; + case 'v': + verbose_level++; + break; + default: + usage(); + break; + } + } + + argc -= optind; + argv += optind; + + /* Common set up */ + isc_lib_register(); + result = dns_lib_init(); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "dns_lib_init failed: %d\n", result); + exit(1); + } + + result = ctxs_init(&mctx, &actx, &taskmgr, &socketmgr, + &timermgr); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "ctx create failed: %d\n", result); + exit(1); + } + + isc_app_ctxstart(actx); + + result = dns_client_createx(mctx, actx, taskmgr, socketmgr, + timermgr, 0, &client); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "dns_client_createx failed: %d\n", result); + exit(1); + } + + /* Set local cache server */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + error = getaddrinfo(cacheserver, "53", &hints, &res); + if (error != 0) { + fprintf(stderr, "failed to convert server name (%s): %s\n", + cacheserver, gai_strerror(error)); + exit(1); + } + + if (res->ai_addrlen > sizeof(sa.type)) { + fprintf(stderr, + "assumption failure: addrlen is too long: %d\n", + res->ai_addrlen); + exit(1); + } + memcpy(&sa.type.sa, res->ai_addr, res->ai_addrlen); + sa.length = res->ai_addrlen; + freeaddrinfo(res); + ISC_LINK_INIT(&sa, link); + ISC_LIST_INIT(servers); + ISC_LIST_APPEND(servers, &sa, link); + result = dns_client_setservers(client, dns_rdataclass_in, NULL, + &servers); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to set server: %d\n", result); + exit(1); + } + + /* Create the main task */ + probe_task = NULL; + result = isc_task_create(taskmgr, 0, &probe_task); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to create task: %d\n", result); + exit(1); + } + + /* Open input file */ + if (argc == 0) + fp = stdin; + else { + fp = fopen(argv[0], "r"); + if (fp == NULL) { + fprintf(stderr, "failed to open input file: %s\n", + argv[0]); + exit(1); + } + } + + /* Set up and start probe */ + for (i = 0; i < MAX_PROBES; i++) { + probes[i].inuse = ISC_FALSE; + probes[i].domain = NULL; + dns_fixedname_init(&probes[i].fixedname); + probes[i].qname = NULL; + probes[i].qlabel = qlabels; + probes[i].qname_found = ISC_FALSE; + probes[i].resid = NULL; + ISC_LIST_INIT(probes[i].nslist); + probes[i].reqid = NULL; + + probes[i].qmessage = NULL; + result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, + &probes[i].qmessage); + if (result == ISC_R_SUCCESS) { + result = dns_message_create(mctx, + DNS_MESSAGE_INTENTPARSE, + &probes[i].rmessage); + } + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "initialization failure\n"); + exit(1); + } + } + for (i = 0; i < MAX_PROBES; i++) { + result = probe_domain(&probes[i]); + if (result == ISC_R_NOMORE) + break; + else if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to issue an initial probe\n"); + exit(1); + } + } + + /* Start event loop */ + isc_app_ctxrun(actx); + + /* Dump results */ + printf("Per domain results (out of %lu domains):\n", + number_of_domains); + printf(" valid: %lu\n" + " ignore: %lu\n" + " nxdomain: %lu\n" + " othererr: %lu\n" + " multiplesoa: %lu\n" + " multiplecname: %lu\n" + " brokenanswer: %lu\n" + " lame: %lu\n" + " unknown: %lu\n" + " multiple errors: %lu\n", + domain_stat.valid, domain_stat.ignore, domain_stat.nxdomain, + domain_stat.othererr, domain_stat.multiplesoa, + domain_stat.multiplecname, domain_stat.brokenanswer, + domain_stat.lame, domain_stat.unknown, multiple_error_domains); + printf("Per server results (out of %lu servers):\n", + number_of_servers); + printf(" valid: %lu\n" + " ignore: %lu\n" + " nxdomain: %lu\n" + " othererr: %lu\n" + " multiplesoa: %lu\n" + " multiplecname: %lu\n" + " brokenanswer: %lu\n" + " lame: %lu\n" + " unknown: %lu\n", + server_stat.valid, server_stat.ignore, server_stat.nxdomain, + server_stat.othererr, server_stat.multiplesoa, + server_stat.multiplecname, server_stat.brokenanswer, + server_stat.lame, server_stat.unknown); + + /* Cleanup */ + for (i = 0; i < MAX_PROBES; i++) { + dns_message_destroy(&probes[i].qmessage); + dns_message_destroy(&probes[i].rmessage); + } + isc_task_detach(&probe_task); + dns_client_destroy(&client); + dns_lib_shutdown(); + isc_app_ctxfinish(actx); + ctxs_destroy(&mctx, &actx, &taskmgr, &socketmgr, &timermgr); + + exit(0); +} diff --git a/lib/export/samples/sample-async.c b/lib/export/samples/sample-async.c new file mode 100644 index 0000000..19c0bba --- /dev/null +++ b/lib/export/samples/sample-async.c @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: sample-async.c,v 1.5 2009-09-29 15:06:07 fdupont Exp $ */ + +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_SERVERS 10 +#define MAX_QUERIES 100 + +static dns_client_t *client = NULL; +static isc_task_t *query_task = NULL; +static isc_appctx_t *query_actx = NULL; +static unsigned int outstanding_queries = 0; +static const char *def_server = "127.0.0.1"; +static FILE *fp; + +struct query_trans { + int id; + isc_boolean_t inuse; + dns_rdatatype_t type; + dns_fixedname_t fixedname; + dns_name_t *qname; + dns_namelist_t answerlist; + dns_clientrestrans_t *xid; +}; + +static struct query_trans query_array[MAX_QUERIES]; + +static isc_result_t dispatch_query(struct query_trans *trans); + +static void +ctxs_destroy(isc_mem_t **mctxp, isc_appctx_t **actxp, + isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp, + isc_timermgr_t **timermgrp) +{ + if (*taskmgrp != NULL) + isc_taskmgr_destroy(taskmgrp); + + if (*timermgrp != NULL) + isc_timermgr_destroy(timermgrp); + + if (*socketmgrp != NULL) + isc_socketmgr_destroy(socketmgrp); + + if (*actxp != NULL) + isc_appctx_destroy(actxp); + + if (*mctxp != NULL) + isc_mem_destroy(mctxp); +} + +static isc_result_t +ctxs_init(isc_mem_t **mctxp, isc_appctx_t **actxp, + isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp, + isc_timermgr_t **timermgrp) +{ + isc_result_t result; + + result = isc_mem_create(0, 0, mctxp); + if (result != ISC_R_SUCCESS) + goto fail; + + result = isc_appctx_create(*mctxp, actxp); + if (result != ISC_R_SUCCESS) + goto fail; + + result = isc_taskmgr_createinctx(*mctxp, *actxp, 1, 0, taskmgrp); + if (result != ISC_R_SUCCESS) + goto fail; + + result = isc_socketmgr_createinctx(*mctxp, *actxp, socketmgrp); + if (result != ISC_R_SUCCESS) + goto fail; + + result = isc_timermgr_createinctx(*mctxp, *actxp, timermgrp); + if (result != ISC_R_SUCCESS) + goto fail; + + return (ISC_R_SUCCESS); + + fail: + ctxs_destroy(mctxp, actxp, taskmgrp, socketmgrp, timermgrp); + + return (result); +} + +static isc_result_t +printdata(dns_rdataset_t *rdataset, dns_name_t *owner) { + isc_buffer_t target; + isc_result_t result; + isc_region_t r; + char t[4096]; + + isc_buffer_init(&target, t, sizeof(t)); + + if (!dns_rdataset_isassociated(rdataset)) + return (ISC_R_SUCCESS); + result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE, + &target); + if (result != ISC_R_SUCCESS) + return (result); + isc_buffer_usedregion(&target, &r); + printf(" %.*s", (int)r.length, (char *)r.base); + + return (ISC_R_SUCCESS); +} + +static void +process_answer(isc_task_t *task, isc_event_t *event) { + struct query_trans *trans = event->ev_arg; + dns_clientresevent_t *rev = (dns_clientresevent_t *)event; + dns_name_t *name; + dns_rdataset_t *rdataset; + isc_result_t result; + + REQUIRE(task == query_task); + REQUIRE(trans->inuse == ISC_TRUE); + REQUIRE(outstanding_queries > 0); + + printf("answer[%2d]\n", trans->id); + + if (rev->result != ISC_R_SUCCESS) + printf(" failed: %d(%s)\n", rev->result, + dns_result_totext(rev->result)); + + for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; + name = ISC_LIST_NEXT(name, link)) { + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + (void)printdata(rdataset, name); + } + } + + dns_client_freeresanswer(client, &rev->answerlist); + dns_client_destroyrestrans(&trans->xid); + + isc_event_free(&event); + + trans->inuse = ISC_FALSE; + dns_fixedname_invalidate(&trans->fixedname); + trans->qname = NULL; + outstanding_queries--; + + result = dispatch_query(trans); +#if 0 /* for cancel test */ + if (result == ISC_R_SUCCESS) { + static int count = 0; + + if ((++count) % 10 == 0) + dns_client_cancelresolve(trans->xid); + } +#endif + if (result == ISC_R_NOMORE && outstanding_queries == 0) + isc_app_ctxshutdown(query_actx); +} + +static isc_result_t +dispatch_query(struct query_trans *trans) { + isc_result_t result; + size_t namelen; + isc_buffer_t b; + char buf[4096]; /* XXX ad hoc constant, but should be enough */ + char *cp; + + REQUIRE(trans != NULL); + REQUIRE(trans->inuse == ISC_FALSE); + REQUIRE(ISC_LIST_EMPTY(trans->answerlist)); + REQUIRE(outstanding_queries < MAX_QUERIES); + + /* Construct qname */ + cp = fgets(buf, sizeof(buf), fp); + if (cp == NULL) + return (ISC_R_NOMORE); + /* zap NL if any */ + if ((cp = strchr(buf, '\n')) != NULL) + *cp = '\0'; + namelen = strlen(buf); + isc_buffer_init(&b, buf, namelen); + isc_buffer_add(&b, namelen); + dns_fixedname_init(&trans->fixedname); + trans->qname = dns_fixedname_name(&trans->fixedname); + result = dns_name_fromtext(trans->qname, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + + /* Start resolution */ + result = dns_client_startresolve(client, trans->qname, + dns_rdataclass_in, trans->type, 0, + query_task, process_answer, trans, + &trans->xid); + if (result != ISC_R_SUCCESS) + goto cleanup; + + trans->inuse = ISC_TRUE; + outstanding_queries++; + + return (ISC_R_SUCCESS); + + cleanup: + dns_fixedname_invalidate(&trans->fixedname); + + return (result); +} + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "usage: sample-async [-s server_address] [-t RR type] " + "input_file\n"); + + exit(1); +} + +int +main(int argc, char *argv[]) { + int ch; + isc_textregion_t tr; + isc_mem_t *mctx = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_socketmgr_t *socketmgr = NULL; + isc_timermgr_t *timermgr = NULL; + int nservers = 0; + const char *serveraddr[MAX_SERVERS]; + isc_sockaddr_t sa[MAX_SERVERS]; + isc_sockaddrlist_t servers; + dns_rdatatype_t type = dns_rdatatype_a; + struct in_addr inaddr; + isc_result_t result; + int i; + + while ((ch = getopt(argc, argv, "s:t:")) != -1) { + switch (ch) { + case 't': + tr.base = optarg; + tr.length = strlen(optarg); + result = dns_rdatatype_fromtext(&type, &tr); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "invalid RRtype: %s\n", optarg); + exit(1); + } + break; + case 's': + if (nservers == MAX_SERVERS) { + fprintf(stderr, + "too many servers (up to %d)\n", + MAX_SERVERS); + exit(1); + } + serveraddr[nservers++] = (const char *)optarg; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc < 1) + usage(); + + if (nservers == 0) { + nservers = 1; + serveraddr[0] = def_server; + } + + for (i = 0; i < MAX_QUERIES; i++) { + query_array[i].id = i; + query_array[i].inuse = ISC_FALSE; + query_array[i].type = type; + dns_fixedname_init(&query_array[i].fixedname); + query_array[i].qname = NULL; + ISC_LIST_INIT(query_array[i].answerlist); + query_array[i].xid = NULL; + } + + isc_lib_register(); + result = dns_lib_init(); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "dns_lib_init failed: %d\n", result); + exit(1); + } + + result = ctxs_init(&mctx, &query_actx, &taskmgr, &socketmgr, + &timermgr); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "ctx create failed: %d\n", result); + exit(1); + } + + isc_app_ctxstart(query_actx); + + result = dns_client_createx(mctx, query_actx, taskmgr, socketmgr, + timermgr, 0, &client); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "dns_client_createx failed: %d\n", result); + exit(1); + } + + /* Set nameservers */ + ISC_LIST_INIT(servers); + for (i = 0; i < nservers; i++) { + if (inet_pton(AF_INET, serveraddr[i], &inaddr) != 1) { + fprintf(stderr, "failed to parse IPv4 address %s\n", + serveraddr[i]); + exit(1); + } + isc_sockaddr_fromin(&sa[i], &inaddr, 53); + ISC_LIST_APPEND(servers, &sa[i], link); + } + result = dns_client_setservers(client, dns_rdataclass_in, NULL, + &servers); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "set server failed: %d\n", result); + exit(1); + } + + /* Create the main task */ + query_task = NULL; + result = isc_task_create(taskmgr, 0, &query_task); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to create task: %d\n", result); + exit(1); + } + + /* Open input file */ + fp = fopen(argv[0], "r"); + if (fp == NULL) { + fprintf(stderr, "failed to open input file: %s\n", argv[1]); + exit(1); + } + + /* Dispatch initial queries */ + for (i = 0; i < MAX_QUERIES; i++) { + result = dispatch_query(&query_array[i]); + if (result == ISC_R_NOMORE) + break; + } + + /* Start event loop */ + isc_app_ctxrun(query_actx); + + /* Sanity check */ + for (i = 0; i < MAX_QUERIES; i++) + INSIST(query_array[i].inuse == ISC_FALSE); + + /* Cleanup */ + isc_task_detach(&query_task); + dns_client_destroy(&client); + dns_lib_shutdown(); + isc_app_ctxfinish(query_actx); + ctxs_destroy(&mctx, &query_actx, &taskmgr, &socketmgr, &timermgr); + + exit(0); +} diff --git a/lib/export/samples/sample-gai.c b/lib/export/samples/sample-gai.c new file mode 100644 index 0000000..7c07f1b --- /dev/null +++ b/lib/export/samples/sample-gai.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: sample-gai.c,v 1.4 2009-09-02 23:48:02 tbox Exp $ */ + +#include + +#include +#include + +#include + +#include +#include +#include + +static void +do_gai(int family, char *hostname) { + struct addrinfo hints, *res, *res0; + int error; + char namebuf[1024], addrbuf[1024], servbuf[1024]; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + error = getaddrinfo(hostname, "http", &hints, &res0); + if (error) { + fprintf(stderr, "getaddrinfo failed for %s,family=%d: %s\n", + hostname, family, gai_strerror(error)); + return; + } + + for (res = res0; res; res = res->ai_next) { + error = getnameinfo(res->ai_addr, res->ai_addrlen, + addrbuf, sizeof(addrbuf), + NULL, 0, NI_NUMERICHOST); + if (error == 0) + error = getnameinfo(res->ai_addr, res->ai_addrlen, + namebuf, sizeof(namebuf), + servbuf, sizeof(servbuf), 0); + if (error != 0) { + fprintf(stderr, "getnameinfo failed: %s\n", + gai_strerror(error)); + } else { + printf("%s(%s/%s)=%s:%s\n", hostname, + res->ai_canonname, addrbuf, namebuf, servbuf); + } + } + + freeaddrinfo(res); +} + +int +main(int argc, char *argv[]) { + if (argc < 2) + exit(1); + + do_gai(AF_INET, argv[1]); + do_gai(AF_INET6, argv[1]); + do_gai(AF_UNSPEC, argv[1]); + + exit(0); +} diff --git a/lib/export/samples/sample-request.c b/lib/export/samples/sample-request.c new file mode 100644 index 0000000..4331498 --- /dev/null +++ b/lib/export/samples/sample-request.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: sample-request.c,v 1.5 2009-09-29 15:06:07 fdupont Exp $ */ + +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static isc_mem_t *mctx; +static dns_fixedname_t fixedqname; + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "sample-request [-t RRtype] server_address hostname\n"); + + exit(1); +} + +static isc_result_t +make_querymessage(dns_message_t *message, const char *namestr, + dns_rdatatype_t rdtype) +{ + dns_name_t *qname = NULL, *qname0; + dns_rdataset_t *qrdataset = NULL; + isc_result_t result; + isc_buffer_t b; + size_t namelen; + + /* Construct qname */ + namelen = strlen(namestr); + isc_buffer_init(&b, namestr, namelen); + isc_buffer_add(&b, namelen); + dns_fixedname_init(&fixedqname); + qname0 = dns_fixedname_name(&fixedqname); + result = dns_name_fromtext(qname0, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to convert qname: %d\n", result); + return (result); + } + + /* Construct query message */ + message->opcode = dns_opcode_query; + message->rdclass = dns_rdataclass_in; + + result = dns_message_gettempname(message, &qname); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dns_message_gettemprdataset(message, &qrdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + + dns_name_init(qname, NULL); + dns_name_clone(qname0, qname); + dns_rdataset_init(qrdataset); + dns_rdataset_makequestion(qrdataset, message->rdclass, rdtype); + ISC_LIST_APPEND(qname->list, qrdataset, link); + dns_message_addname(message, qname, DNS_SECTION_QUESTION); + + return (ISC_R_SUCCESS); + + cleanup: + if (qname != NULL) + dns_message_puttempname(message, &qname); + if (qrdataset != NULL) + dns_message_puttemprdataset(message, &qrdataset); + if (message != NULL) + dns_message_destroy(&message); + return (result); +} + +static void +print_section(dns_message_t *message, int section, isc_buffer_t *buf) { + isc_result_t result; + isc_region_t r; + + result = dns_message_sectiontotext(message, section, + &dns_master_style_full, 0, buf); + if (result != ISC_R_SUCCESS) + goto fail; + + isc_buffer_usedregion(buf, &r); + printf("%.*s", (int)r.length, (char *)r.base); + + return; + + fail: + fprintf(stderr, "failed to convert a section\n"); +} + +int +main(int argc, char *argv[]) { + int ch, i, gai_error; + struct addrinfo hints, *res; + isc_textregion_t tr; + dns_client_t *client = NULL; + isc_result_t result; + isc_sockaddr_t sa; + dns_message_t *qmessage, *rmessage; + dns_rdatatype_t type = dns_rdatatype_a; + isc_buffer_t *outputbuf; + + while ((ch = getopt(argc, argv, "t:")) != -1) { + switch (ch) { + case 't': + tr.base = optarg; + tr.length = strlen(optarg); + result = dns_rdatatype_fromtext(&type, &tr); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "invalid RRtype: %s\n", optarg); + exit(1); + } + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc < 2) + usage(); + + isc_lib_register(); + result = dns_lib_init(); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "dns_lib_init failed: %d\n", result); + exit(1); + } + + result = dns_client_create(&client, 0); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "dns_client_create failed: %d\n", result); + exit(1); + } + + /* Prepare message structures */ + mctx = NULL; + qmessage = NULL; + rmessage = NULL; + + result = isc_mem_create(0, 0, &mctx); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to create a memory context\n"); + exit(1); + } + result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &qmessage); + if (result == ISC_R_SUCCESS) { + result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, + &rmessage); + } + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to create messages\n"); + exit(1); + } + + /* Initialize the nameserver address */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_NUMERICHOST; + gai_error = getaddrinfo(argv[0], "53", &hints, &res); + if (gai_error != 0) { + fprintf(stderr, "getaddrinfo failed: %s\n", + gai_strerror(gai_error)); + exit(1); + } + INSIST(res->ai_addrlen <= sizeof(sa.type)); + memcpy(&sa.type, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + sa.length = res->ai_addrlen; + ISC_LINK_INIT(&sa, link); + + /* Construct qname */ + result = make_querymessage(qmessage, argv[1], type); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to create a query\n"); + exit(1); + } + + /* Send request and wait for a response */ + result = dns_client_request(client, qmessage, rmessage, &sa, 0, 0, + NULL, 60, 0, 3); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to get a response: %s\n", + dns_result_totext(result)); + } + + /* Dump the response */ + outputbuf = NULL; + result = isc_buffer_allocate(mctx, &outputbuf, 65535); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to allocate a result buffer\n"); + exit(1); + } + for (i = 0; i < DNS_SECTION_MAX; i++) { + print_section(rmessage, i, outputbuf); + isc_buffer_clear(outputbuf); + } + isc_buffer_free(&outputbuf); + + /* Cleanup */ + dns_message_destroy(&qmessage); + dns_message_destroy(&rmessage); + isc_mem_destroy(&mctx); + dns_client_destroy(&client); + dns_lib_shutdown(); + + exit(0); +} diff --git a/lib/export/samples/sample-update.c b/lib/export/samples/sample-update.c new file mode 100644 index 0000000..eef0a58 --- /dev/null +++ b/lib/export/samples/sample-update.c @@ -0,0 +1,755 @@ +/* + * Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: sample-update.c,v 1.10 2010-12-09 00:54:34 marka Exp $ */ + +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static dns_tsec_t *tsec = NULL; +static const dns_rdataclass_t default_rdataclass = dns_rdataclass_in; +static isc_bufferlist_t usedbuffers; +static ISC_LIST(dns_rdatalist_t) usedrdatalists; + +static void setup_tsec(char *keyfile, isc_mem_t *mctx); +static void update_addordelete(isc_mem_t *mctx, char *cmdline, + isc_boolean_t isdelete, dns_name_t *name); +static void evaluate_prereq(isc_mem_t *mctx, char *cmdline, dns_name_t *name); + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "sample-update " + "[-a auth_server] " + "[-k keyfile] " + "[-p prerequisite] " + "[-r recursive_server] " + "[-z zonename] " + "(add|delete) \"name TTL RRtype RDATA\"\n"); + exit(1); +} + +int +main(int argc, char *argv[]) { + int ch; + struct addrinfo hints, *res; + int gai_error; + dns_client_t *client = NULL; + char *zonenamestr = NULL; + char *keyfilename = NULL; + char *prereqstr = NULL; + isc_sockaddrlist_t auth_servers; + char *auth_server = NULL; + char *recursive_server = NULL; + isc_sockaddr_t sa_auth, sa_recursive; + isc_sockaddrlist_t rec_servers; + isc_result_t result; + isc_boolean_t isdelete; + isc_buffer_t b, *buf; + dns_fixedname_t zname0, pname0, uname0; + size_t namelen; + dns_name_t *zname = NULL, *uname, *pname; + dns_rdataset_t *rdataset; + dns_rdatalist_t *rdatalist; + dns_rdata_t *rdata; + dns_namelist_t updatelist, prereqlist, *prereqlistp = NULL; + isc_mem_t *umctx = NULL; + + while ((ch = getopt(argc, argv, "a:k:p:r:z:")) != -1) { + switch (ch) { + case 'k': + keyfilename = optarg; + break; + case 'a': + auth_server = optarg; + break; + case 'p': + prereqstr = optarg; + break; + case 'r': + recursive_server = optarg; + break; + case 'z': + zonenamestr = optarg; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc < 2) + usage(); + + /* command line argument validation */ + if (strcmp(argv[0], "delete") == 0) + isdelete = ISC_TRUE; + else if (strcmp(argv[0], "add") == 0) + isdelete = ISC_FALSE; + else { + fprintf(stderr, "invalid update command: %s\n", argv[0]); + exit(1); + } + + if (auth_server == NULL && recursive_server == NULL) { + fprintf(stderr, "authoritative or recursive server " + "must be specified\n"); + usage(); + } + + /* Initialization */ + ISC_LIST_INIT(usedbuffers); + ISC_LIST_INIT(usedrdatalists); + ISC_LIST_INIT(prereqlist); + ISC_LIST_INIT(auth_servers); + isc_lib_register(); + result = dns_lib_init(); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "dns_lib_init failed: %d\n", result); + exit(1); + } + result = isc_mem_create(0, 0, &umctx); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to crate mctx\n"); + exit(1); + } + + result = dns_client_create(&client, 0); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "dns_client_create failed: %d\n", result); + exit(1); + } + + /* Set the authoritative server */ + if (auth_server != NULL) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_NUMERICHOST; + gai_error = getaddrinfo(auth_server, "53", &hints, &res); + if (gai_error != 0) { + fprintf(stderr, "getaddrinfo failed: %s\n", + gai_strerror(gai_error)); + exit(1); + } + INSIST(res->ai_addrlen <= sizeof(sa_auth.type)); + memcpy(&sa_auth.type, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + sa_auth.length = res->ai_addrlen; + ISC_LINK_INIT(&sa_auth, link); + + ISC_LIST_APPEND(auth_servers, &sa_auth, link); + } + + /* Set the recursive server */ + if (recursive_server != NULL) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_NUMERICHOST; + gai_error = getaddrinfo(recursive_server, "53", &hints, &res); + if (gai_error != 0) { + fprintf(stderr, "getaddrinfo failed: %s\n", + gai_strerror(gai_error)); + exit(1); + } + INSIST(res->ai_addrlen <= sizeof(sa_recursive.type)); + memcpy(&sa_recursive.type, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + sa_recursive.length = res->ai_addrlen; + ISC_LINK_INIT(&sa_recursive, link); + ISC_LIST_INIT(rec_servers); + ISC_LIST_APPEND(rec_servers, &sa_recursive, link); + result = dns_client_setservers(client, dns_rdataclass_in, + NULL, &rec_servers); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "set server failed: %d\n", result); + exit(1); + } + } + + /* Construct zone name */ + zname = NULL; + if (zonenamestr != NULL) { + namelen = strlen(zonenamestr); + isc_buffer_init(&b, zonenamestr, namelen); + isc_buffer_add(&b, namelen); + dns_fixedname_init(&zname0); + zname = dns_fixedname_name(&zname0); + result = dns_name_fromtext(zname, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) + fprintf(stderr, "failed to convert zone name: %d\n", + result); + } + + /* Construct prerequisite name (if given) */ + if (prereqstr != NULL) { + dns_fixedname_init(&pname0); + pname = dns_fixedname_name(&pname0); + evaluate_prereq(umctx, prereqstr, pname); + ISC_LIST_APPEND(prereqlist, pname, link); + prereqlistp = &prereqlist; + } + + /* Construct update name */ + ISC_LIST_INIT(updatelist); + dns_fixedname_init(&uname0); + uname = dns_fixedname_name(&uname0); + update_addordelete(umctx, argv[1], isdelete, uname); + ISC_LIST_APPEND(updatelist, uname, link); + + /* Set up TSIG/SIG(0) key (if given) */ + if (keyfilename != NULL) + setup_tsec(keyfilename, umctx); + + /* Perform update */ + result = dns_client_update(client, + default_rdataclass, /* XXX: fixed */ + zname, prereqlistp, &updatelist, + (auth_server == NULL) ? NULL : + &auth_servers, tsec, 0); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "update failed: %s\n", dns_result_totext(result)); + } else + fprintf(stderr, "update succeeded\n"); + + /* Cleanup */ + while ((pname = ISC_LIST_HEAD(prereqlist)) != NULL) { + while ((rdataset = ISC_LIST_HEAD(pname->list)) != NULL) { + ISC_LIST_UNLINK(pname->list, rdataset, link); + dns_rdataset_disassociate(rdataset); + isc_mem_put(umctx, rdataset, sizeof(*rdataset)); + } + ISC_LIST_UNLINK(prereqlist, pname, link); + } + while ((uname = ISC_LIST_HEAD(updatelist)) != NULL) { + while ((rdataset = ISC_LIST_HEAD(uname->list)) != NULL) { + ISC_LIST_UNLINK(uname->list, rdataset, link); + dns_rdataset_disassociate(rdataset); + isc_mem_put(umctx, rdataset, sizeof(*rdataset)); + } + ISC_LIST_UNLINK(updatelist, uname, link); + } + while ((rdatalist = ISC_LIST_HEAD(usedrdatalists)) != NULL) { + while ((rdata = ISC_LIST_HEAD(rdatalist->rdata)) != NULL) { + ISC_LIST_UNLINK(rdatalist->rdata, rdata, link); + isc_mem_put(umctx, rdata, sizeof(*rdata)); + } + ISC_LIST_UNLINK(usedrdatalists, rdatalist, link); + isc_mem_put(umctx, rdatalist, sizeof(*rdatalist)); + } + while ((buf = ISC_LIST_HEAD(usedbuffers)) != NULL) { + ISC_LIST_UNLINK(usedbuffers, buf, link); + isc_buffer_free(&buf); + } + if (tsec != NULL) + dns_tsec_destroy(&tsec); + isc_mem_destroy(&umctx); + dns_client_destroy(&client); + dns_lib_shutdown(); + + exit(0); +} + +/* + * Subroutines borrowed from nsupdate.c + */ +#define MAXWIRE (64 * 1024) +#define TTL_MAX 2147483647U /* Maximum signed 32 bit integer. */ + +static char * +nsu_strsep(char **stringp, const char *delim) { + char *string = *stringp; + char *s; + const char *d; + char sc, dc; + + if (string == NULL) + return (NULL); + + for (; *string != '\0'; string++) { + sc = *string; + for (d = delim; (dc = *d) != '\0'; d++) { + if (sc == dc) + break; + } + if (dc == 0) + break; + } + + for (s = string; *s != '\0'; s++) { + sc = *s; + for (d = delim; (dc = *d) != '\0'; d++) { + if (sc == dc) { + *s++ = '\0'; + *stringp = s; + return (string); + } + } + } + *stringp = NULL; + return (string); +} + +static void +fatal(const char *format, ...) { + va_list args; + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + exit(1); +} + +static inline void +check_result(isc_result_t result, const char *msg) { + if (result != ISC_R_SUCCESS) + fatal("%s: %s", msg, isc_result_totext(result)); +} + +static void +parse_name(char **cmdlinep, dns_name_t *name) { + isc_result_t result; + char *word; + isc_buffer_t source; + + word = nsu_strsep(cmdlinep, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read owner name\n"); + exit(1); + } + + isc_buffer_init(&source, word, strlen(word)); + isc_buffer_add(&source, strlen(word)); + result = dns_name_fromtext(name, &source, dns_rootname, 0, NULL); + check_result(result, "dns_name_fromtext"); + isc_buffer_invalidate(&source); +} + +static void +parse_rdata(isc_mem_t *mctx, char **cmdlinep, dns_rdataclass_t rdataclass, + dns_rdatatype_t rdatatype, dns_rdata_t *rdata) +{ + char *cmdline = *cmdlinep; + isc_buffer_t source, *buf = NULL, *newbuf = NULL; + isc_region_t r; + isc_lex_t *lex = NULL; + dns_rdatacallbacks_t callbacks; + isc_result_t result; + + while (cmdline != NULL && *cmdline != 0 && + isspace((unsigned char)*cmdline)) + cmdline++; + + if (cmdline != NULL && *cmdline != 0) { + dns_rdatacallbacks_init(&callbacks); + result = isc_lex_create(mctx, strlen(cmdline), &lex); + check_result(result, "isc_lex_create"); + isc_buffer_init(&source, cmdline, strlen(cmdline)); + isc_buffer_add(&source, strlen(cmdline)); + result = isc_lex_openbuffer(lex, &source); + check_result(result, "isc_lex_openbuffer"); + result = isc_buffer_allocate(mctx, &buf, MAXWIRE); + check_result(result, "isc_buffer_allocate"); + result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex, + dns_rootname, 0, mctx, buf, + &callbacks); + isc_lex_destroy(&lex); + if (result == ISC_R_SUCCESS) { + isc_buffer_usedregion(buf, &r); + result = isc_buffer_allocate(mctx, &newbuf, r.length); + check_result(result, "isc_buffer_allocate"); + isc_buffer_putmem(newbuf, r.base, r.length); + isc_buffer_usedregion(newbuf, &r); + dns_rdata_reset(rdata); + dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r); + isc_buffer_free(&buf); + ISC_LIST_APPEND(usedbuffers, newbuf, link); + } else { + fprintf(stderr, "invalid rdata format: %s\n", + isc_result_totext(result)); + isc_buffer_free(&buf); + exit(1); + } + } else { + rdata->flags = DNS_RDATA_UPDATE; + } + *cmdlinep = cmdline; +} + +static void +update_addordelete(isc_mem_t *mctx, char *cmdline, isc_boolean_t isdelete, + dns_name_t *name) +{ + isc_result_t result; + isc_uint32_t ttl; + char *word; + dns_rdataclass_t rdataclass; + dns_rdatatype_t rdatatype; + dns_rdata_t *rdata = NULL; + dns_rdatalist_t *rdatalist = NULL; + dns_rdataset_t *rdataset = NULL; + isc_textregion_t region; + + /* + * Read the owner name. + */ + parse_name(&cmdline, name); + + rdata = isc_mem_get(mctx, sizeof(*rdata)); + if (rdata == NULL) { + fprintf(stderr, "memory allocation for rdata failed\n"); + exit(1); + } + dns_rdata_init(rdata); + + /* + * If this is an add, read the TTL and verify that it's in range. + * If it's a delete, ignore a TTL if present (for compatibility). + */ + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + if (!isdelete) { + fprintf(stderr, "could not read owner ttl\n"); + exit(1); + } + else { + ttl = 0; + rdataclass = dns_rdataclass_any; + rdatatype = dns_rdatatype_any; + rdata->flags = DNS_RDATA_UPDATE; + goto doneparsing; + } + } + result = isc_parse_uint32(&ttl, word, 10); + if (result != ISC_R_SUCCESS) { + if (isdelete) { + ttl = 0; + goto parseclass; + } else { + fprintf(stderr, "ttl '%s': %s\n", word, + isc_result_totext(result)); + exit(1); + } + } + + if (isdelete) + ttl = 0; + else if (ttl > TTL_MAX) { + fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", + word, TTL_MAX); + exit(1); + } + + /* + * Read the class or type. + */ + word = nsu_strsep(&cmdline, " \t\r\n"); + parseclass: + if (word == NULL || *word == 0) { + if (isdelete) { + rdataclass = dns_rdataclass_any; + rdatatype = dns_rdatatype_any; + rdata->flags = DNS_RDATA_UPDATE; + goto doneparsing; + } else { + fprintf(stderr, "could not read class or type\n"); + exit(1); + } + } + region.base = word; + region.length = strlen(word); + result = dns_rdataclass_fromtext(&rdataclass, ®ion); + if (result == ISC_R_SUCCESS) { + /* + * Now read the type. + */ + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + if (isdelete) { + rdataclass = dns_rdataclass_any; + rdatatype = dns_rdatatype_any; + rdata->flags = DNS_RDATA_UPDATE; + goto doneparsing; + } else { + fprintf(stderr, "could not read type\n"); + exit(1); + } + } + region.base = word; + region.length = strlen(word); + result = dns_rdatatype_fromtext(&rdatatype, ®ion); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "'%s' is not a valid type: %s\n", + word, isc_result_totext(result)); + exit(1); + } + } else { + rdataclass = default_rdataclass; + result = dns_rdatatype_fromtext(&rdatatype, ®ion); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "'%s' is not a valid class or type: " + "%s\n", word, isc_result_totext(result)); + exit(1); + } + } + + parse_rdata(mctx, &cmdline, rdataclass, rdatatype, rdata); + + if (isdelete) { + if ((rdata->flags & DNS_RDATA_UPDATE) != 0) + rdataclass = dns_rdataclass_any; + else + rdataclass = dns_rdataclass_none; + } else { + if ((rdata->flags & DNS_RDATA_UPDATE) != 0) { + fprintf(stderr, "could not read rdata\n"); + exit(1); + } + } + + doneparsing: + + rdatalist = isc_mem_get(mctx, sizeof(*rdatalist)); + if (rdatalist == NULL) { + fprintf(stderr, "memory allocation for rdatalist failed\n"); + exit(1); + } + dns_rdatalist_init(rdatalist); + rdatalist->type = rdatatype; + rdatalist->rdclass = rdataclass; + rdatalist->covers = rdatatype; + rdatalist->ttl = (dns_ttl_t)ttl; + ISC_LIST_INIT(rdatalist->rdata); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + ISC_LIST_APPEND(usedrdatalists, rdatalist, link); + + rdataset = isc_mem_get(mctx, sizeof(*rdataset)); + if (rdataset == NULL) { + fprintf(stderr, "memory allocation for rdataset failed\n"); + exit(1); + } + dns_rdataset_init(rdataset); + dns_rdatalist_tordataset(rdatalist, rdataset); + ISC_LIST_INIT(name->list); + ISC_LIST_APPEND(name->list, rdataset, link); +} + +static void +make_prereq(isc_mem_t *mctx, char *cmdline, isc_boolean_t ispositive, + isc_boolean_t isrrset, dns_name_t *name) +{ + isc_result_t result; + char *word; + isc_textregion_t region; + dns_rdataset_t *rdataset = NULL; + dns_rdatalist_t *rdatalist = NULL; + dns_rdataclass_t rdataclass; + dns_rdatatype_t rdatatype; + dns_rdata_t *rdata = NULL; + + /* + * Read the owner name + */ + parse_name(&cmdline, name); + + /* + * If this is an rrset prereq, read the class or type. + */ + if (isrrset) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read class or type\n"); + exit(1); + } + region.base = word; + region.length = strlen(word); + result = dns_rdataclass_fromtext(&rdataclass, ®ion); + if (result == ISC_R_SUCCESS) { + /* + * Now read the type. + */ + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read type\n"); + exit(1); + } + region.base = word; + region.length = strlen(word); + result = dns_rdatatype_fromtext(&rdatatype, ®ion); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "invalid type: %s\n", word); + exit(1); + } + } else { + rdataclass = default_rdataclass; + result = dns_rdatatype_fromtext(&rdatatype, ®ion); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "invalid type: %s\n", word); + exit(1); + } + } + } else + rdatatype = dns_rdatatype_any; + + rdata = isc_mem_get(mctx, sizeof(*rdata)); + if (rdata == NULL) { + fprintf(stderr, "memory allocation for rdata failed\n"); + exit(1); + } + dns_rdata_init(rdata); + + if (isrrset && ispositive) + parse_rdata(mctx, &cmdline, rdataclass, rdatatype, rdata); + else + rdata->flags = DNS_RDATA_UPDATE; + + rdatalist = isc_mem_get(mctx, sizeof(*rdatalist)); + if (rdatalist == NULL) { + fprintf(stderr, "memory allocation for rdatalist failed\n"); + exit(1); + } + dns_rdatalist_init(rdatalist); + rdatalist->type = rdatatype; + if (ispositive) { + if (isrrset && rdata->data != NULL) + rdatalist->rdclass = rdataclass; + else + rdatalist->rdclass = dns_rdataclass_any; + } else + rdatalist->rdclass = dns_rdataclass_none; + rdatalist->covers = 0; + rdatalist->ttl = 0; + rdata->rdclass = rdatalist->rdclass; + rdata->type = rdatatype; + ISC_LIST_INIT(rdatalist->rdata); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + ISC_LIST_APPEND(usedrdatalists, rdatalist, link); + + rdataset = isc_mem_get(mctx, sizeof(*rdataset)); + if (rdataset == NULL) { + fprintf(stderr, "memory allocation for rdataset failed\n"); + exit(1); + } + dns_rdataset_init(rdataset); + dns_rdatalist_tordataset(rdatalist, rdataset); + ISC_LIST_INIT(name->list); + ISC_LIST_APPEND(name->list, rdataset, link); +} + +static void +evaluate_prereq(isc_mem_t *mctx, char *cmdline, dns_name_t *name) { + char *word; + isc_boolean_t ispositive, isrrset; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL || *word == 0) { + fprintf(stderr, "could not read operation code\n"); + exit(1); + } + if (strcasecmp(word, "nxdomain") == 0) { + ispositive = ISC_FALSE; + isrrset = ISC_FALSE; + } else if (strcasecmp(word, "yxdomain") == 0) { + ispositive = ISC_TRUE; + isrrset = ISC_FALSE; + } else if (strcasecmp(word, "nxrrset") == 0) { + ispositive = ISC_FALSE; + isrrset = ISC_TRUE; + } else if (strcasecmp(word, "yxrrset") == 0) { + ispositive = ISC_TRUE; + isrrset = ISC_TRUE; + } else { + fprintf(stderr, "incorrect operation code: %s\n", word); + exit(1); + } + + make_prereq(mctx, cmdline, ispositive, isrrset, name); +} + +static void +setup_tsec(char *keyfile, isc_mem_t *mctx) { + dst_key_t *dstkey = NULL; + isc_result_t result; + dns_tsectype_t tsectype; + + result = dst_key_fromnamedfile(keyfile, NULL, + DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, + &dstkey); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not read key from %s: %s\n", + keyfile, isc_result_totext(result)); + exit(1); + } + + if (dst_key_alg(dstkey) == DST_ALG_HMACMD5) + tsectype = dns_tsectype_tsig; + else + tsectype = dns_tsectype_sig0; + + result = dns_tsec_create(mctx, tsectype, dstkey, &tsec); + dst_key_free(&dstkey); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create tsec: %s\n", + isc_result_totext(result)); + exit(1); + } +} diff --git a/lib/export/samples/sample.c b/lib/export/samples/sample.c new file mode 100644 index 0000000..6564f0e --- /dev/null +++ b/lib/export/samples/sample.c @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: sample.c,v 1.5 2009-09-29 15:06:07 fdupont Exp $ */ + +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static char *algname; + +static isc_result_t +printdata(dns_rdataset_t *rdataset, dns_name_t *owner) { + isc_buffer_t target; + isc_result_t result; + isc_region_t r; + char t[4096]; + + if (!dns_rdataset_isassociated(rdataset)) { + printf("[WARN: empty]\n"); + return (ISC_R_SUCCESS); + } + + isc_buffer_init(&target, t, sizeof(t)); + + result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE, + &target); + if (result != ISC_R_SUCCESS) + return (result); + isc_buffer_usedregion(&target, &r); + printf("%.*s", (int)r.length, (char *)r.base); + + return (ISC_R_SUCCESS); +} + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fprintf(stderr, "sample [-t RRtype] " + "[[-a algorithm] [-e] -k keyname -K keystring] " + "[-s domain:serveraddr_for_domain ] " + "server_address hostname\n"); + + exit(1); +} + +static void +set_key(dns_client_t *client, char *keynamestr, char *keystr, + isc_boolean_t is_sep, isc_mem_t **mctxp) +{ + isc_result_t result; + dns_fixedname_t fkeyname; + size_t namelen; + dns_name_t *keyname; + dns_rdata_dnskey_t keystruct; + unsigned char keydata[4096]; + isc_buffer_t keydatabuf; + unsigned char rrdata[4096]; + isc_buffer_t rrdatabuf; + isc_buffer_t b; + isc_textregion_t tr; + isc_region_t r; + dns_secalg_t alg; + + result = isc_mem_create(0, 0, mctxp); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to crate mctx\n"); + exit(1); + } + + if (algname != NULL) { + tr.base = algname; + tr.length = strlen(algname); + result = dns_secalg_fromtext(&alg, &tr); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to identify the algorithm\n"); + exit(1); + } + } else + alg = DNS_KEYALG_RSASHA1; + + keystruct.common.rdclass = dns_rdataclass_in; + keystruct.common.rdtype = dns_rdatatype_dnskey; + keystruct.flags = DNS_KEYOWNER_ZONE; /* fixed */ + if (is_sep) + keystruct.flags |= DNS_KEYFLAG_KSK; + keystruct.protocol = DNS_KEYPROTO_DNSSEC; /* fixed */ + keystruct.algorithm = alg; + + isc_buffer_init(&keydatabuf, keydata, sizeof(keydata)); + isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); + result = isc_base64_decodestring(keystr, &keydatabuf); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "base64 decode failed\n"); + exit(1); + } + isc_buffer_usedregion(&keydatabuf, &r); + keystruct.datalen = r.length; + keystruct.data = r.base; + + result = dns_rdata_fromstruct(NULL, keystruct.common.rdclass, + keystruct.common.rdtype, + &keystruct, &rrdatabuf); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to construct key rdata\n"); + exit(1); + } + namelen = strlen(keynamestr); + isc_buffer_init(&b, keynamestr, namelen); + isc_buffer_add(&b, namelen); + dns_fixedname_init(&fkeyname); + keyname = dns_fixedname_name(&fkeyname); + result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to construct key name\n"); + exit(1); + } + result = dns_client_addtrustedkey(client, dns_rdataclass_in, + keyname, &rrdatabuf); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to add key for %s\n", + keynamestr); + exit(1); + } +} + +static void +addserver(dns_client_t *client, const char *addrstr, const char *namespace) { + struct addrinfo hints, *res; + int gai_error; + isc_sockaddr_t sa; + isc_sockaddrlist_t servers; + isc_result_t result; + size_t namelen; + isc_buffer_t b; + dns_fixedname_t fname; + dns_name_t *name = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_NUMERICHOST; + gai_error = getaddrinfo(addrstr, "53", &hints, &res); + if (gai_error != 0) { + fprintf(stderr, "getaddrinfo failed: %s\n", + gai_strerror(gai_error)); + exit(1); + } + INSIST(res->ai_addrlen <= sizeof(sa.type)); + memcpy(&sa.type, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + sa.length = res->ai_addrlen; + ISC_LINK_INIT(&sa, link); + ISC_LIST_INIT(servers); + ISC_LIST_APPEND(servers, &sa, link); + + if (namespace != NULL) { + namelen = strlen(namespace); + isc_buffer_init(&b, namespace, namelen); + isc_buffer_add(&b, namelen); + dns_fixedname_init(&fname); + name = dns_fixedname_name(&fname); + result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "failed to convert qname: %d\n", + result); + exit(1); + } + } + + result = dns_client_setservers(client, dns_rdataclass_in, name, + &servers); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "set server failed: %d\n", result); + exit(1); + } +} + +int +main(int argc, char *argv[]) { + int ch; + isc_textregion_t tr; + char *altserver = NULL; + char *altserveraddr = NULL; + char *altservername = NULL; + dns_client_t *client = NULL; + char *keynamestr = NULL; + char *keystr = NULL; + isc_result_t result; + isc_buffer_t b; + dns_fixedname_t qname0; + size_t namelen; + dns_name_t *qname, *name; + dns_rdatatype_t type = dns_rdatatype_a; + dns_rdataset_t *rdataset; + dns_namelist_t namelist; + isc_mem_t *keymctx = NULL; + unsigned int clientopt, resopt; + isc_boolean_t is_sep = ISC_FALSE; + + while ((ch = getopt(argc, argv, "a:es:t:k:K:")) != -1) { + switch (ch) { + case 't': + tr.base = optarg; + tr.length = strlen(optarg); + result = dns_rdatatype_fromtext(&type, &tr); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "invalid RRtype: %s\n", optarg); + exit(1); + } + break; + case 'a': + algname = optarg; + break; + case 'e': + is_sep = ISC_TRUE; + break; + case 's': + if (altserver != NULL) { + fprintf(stderr, "alternate server " + "already defined: %s\n", + altserver); + exit(1); + } + altserver = optarg; + break; + case 'k': + keynamestr = optarg; + break; + case 'K': + keystr = optarg; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc < 2) + usage(); + + if (altserver != NULL) { + char *cp; + + cp = strchr(altserver, ':'); + if (cp == NULL) { + fprintf(stderr, "invalid alternate server: %s\n", + altserver); + exit(1); + } + *cp = '\0'; + altservername = altserver; + altserveraddr = cp + 1; + } + + isc_lib_register(); + result = dns_lib_init(); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "dns_lib_init failed: %d\n", result); + exit(1); + } + + clientopt = 0; + result = dns_client_create(&client, clientopt); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "dns_client_create failed: %d\n", result); + exit(1); + } + + /* Set the nameserver */ + addserver(client, argv[0], NULL); + + /* Set the alternate nameserver (when specified) */ + if (altserver != NULL) + addserver(client, altserveraddr, altservername); + + /* Install DNSSEC key (if given) */ + if (keynamestr != NULL) { + if (keystr == NULL) { + fprintf(stderr, + "key string is missing " + "while key name is provided\n"); + exit(1); + } + set_key(client, keynamestr, keystr, is_sep, &keymctx); + } + + /* Construct qname */ + namelen = strlen(argv[1]); + isc_buffer_init(&b, argv[1], namelen); + isc_buffer_add(&b, namelen); + dns_fixedname_init(&qname0); + qname = dns_fixedname_name(&qname0); + result = dns_name_fromtext(qname, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) + fprintf(stderr, "failed to convert qname: %d\n", result); + + /* Perform resolution */ + resopt = 0; + if (keynamestr == NULL) + resopt |= DNS_CLIENTRESOPT_NODNSSEC; + ISC_LIST_INIT(namelist); + result = dns_client_resolve(client, qname, dns_rdataclass_in, type, + resopt, &namelist); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, + "resolution failed: %s\n", dns_result_totext(result)); + } + for (name = ISC_LIST_HEAD(namelist); name != NULL; + name = ISC_LIST_NEXT(name, link)) { + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + if (printdata(rdataset, name) != ISC_R_SUCCESS) + fprintf(stderr, "print data failed\n"); + } + } + + dns_client_freeresanswer(client, &namelist); + + /* Cleanup */ + dns_client_destroy(&client); + if (keynamestr != NULL) + isc_mem_destroy(&keymctx); + dns_lib_shutdown(); + + exit(0); +} diff --git a/lib/irs/Makefile.in b/lib/irs/Makefile.in new file mode 100644 index 0000000..3f9bfb3 --- /dev/null +++ b/lib/irs/Makefile.in @@ -0,0 +1,80 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_VERSION@ + +@LIBIRS_API@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I. -I./include -I${srcdir}/include \ + ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} + +CDEFINES = +CWARNINGS = + +# Alphabetically +OBJS = context.@O@ \ + dnsconf.@O@ \ + gai_strerror.@O@ getaddrinfo.@O@ getnameinfo.@O@ \ + resconf.@O@ + +# Alphabetically +SRCS = context.c \ + dnsconf.c \ + gai_sterror.c getaddrinfo.c getnameinfo.c \ + resconf.c + +LIBS = @LIBS@ + +SUBDIRS = include +TARGETS = timestamp + +@BIND9_MAKE_RULES@ + +version.@O@: version.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DVERSION=\"${VERSION}\" \ + -DLIBINTERFACE=${LIBINTERFACE} \ + -DLIBREVISION=${LIBREVISION} \ + -DLIBAGE=${LIBAGE} \ + -c ${srcdir}/version.c + +libirs.@SA@: ${OBJS} version.@O@ + ${AR} ${ARFLAGS} $@ ${OBJS} version.@O@ + ${RANLIB} $@ + +libirs.la: ${OBJS} version.@O@ + ${LIBTOOL_MODE_LINK} \ + ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libirs.la -rpath ${libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} version.@O@ ${LIBS} + +timestamp: libirs.@A@ + touch timestamp + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir} + +install:: timestamp installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libirs.@A@ ${DESTDIR}${libdir} + +clean distclean:: + rm -f libirs.@A@ libirs.la timestamp diff --git a/lib/irs/api b/lib/irs/api new file mode 100644 index 0000000..94575eb --- /dev/null +++ b/lib/irs/api @@ -0,0 +1,3 @@ +LIBINTERFACE = 80 +LIBREVISION = 0 +LIBAGE = 0 diff --git a/lib/irs/context.c b/lib/irs/context.c new file mode 100644 index 0000000..0c6d856 --- /dev/null +++ b/lib/irs/context.c @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: context.c,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define IRS_CONTEXT_MAGIC ISC_MAGIC('I', 'R', 'S', 'c') +#define IRS_CONTEXT_VALID(c) ISC_MAGIC_VALID(c, IRS_CONTEXT_MAGIC) + +#ifndef RESOLV_CONF +/*% location of resolve.conf */ +#define RESOLV_CONF "/etc/resolv.conf" +#endif + +#ifndef DNS_CONF +/*% location of dns.conf */ +#define DNS_CONF "/etc/dns.conf" +#endif + +#ifndef ISC_PLATFORM_USETHREADS +irs_context_t *irs_g_context = NULL; +#else +static isc_boolean_t thread_key_initialized = ISC_FALSE; +static isc_mutex_t thread_key_mutex; +static isc_thread_key_t irs_context_key; +static isc_once_t once = ISC_ONCE_INIT; +#endif + + +struct irs_context { + /* + * An IRS context is a thread-specific object, and does not need to + * be locked. + */ + unsigned int magic; + isc_mem_t *mctx; + isc_appctx_t *actx; + isc_taskmgr_t *taskmgr; + isc_task_t *task; + isc_socketmgr_t *socketmgr; + isc_timermgr_t *timermgr; + dns_client_t *dnsclient; + irs_resconf_t *resconf; + irs_dnsconf_t *dnsconf; +}; + +static void +ctxs_destroy(isc_mem_t **mctxp, isc_appctx_t **actxp, + isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp, + isc_timermgr_t **timermgrp) +{ + if (taskmgrp != NULL) + isc_taskmgr_destroy(taskmgrp); + + if (timermgrp != NULL) + isc_timermgr_destroy(timermgrp); + + if (socketmgrp != NULL) + isc_socketmgr_destroy(socketmgrp); + + if (actxp != NULL) + isc_appctx_destroy(actxp); + + if (mctxp != NULL) + isc_mem_destroy(mctxp); +} + +static isc_result_t +ctxs_init(isc_mem_t **mctxp, isc_appctx_t **actxp, + isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp, + isc_timermgr_t **timermgrp) +{ + isc_result_t result; + + result = isc_mem_create(0, 0, mctxp); + if (result != ISC_R_SUCCESS) + goto fail; + + result = isc_appctx_create(*mctxp, actxp); + if (result != ISC_R_SUCCESS) + goto fail; + + result = isc_taskmgr_createinctx(*mctxp, *actxp, 1, 0, taskmgrp); + if (result != ISC_R_SUCCESS) + goto fail; + + result = isc_socketmgr_createinctx(*mctxp, *actxp, socketmgrp); + if (result != ISC_R_SUCCESS) + goto fail; + + result = isc_timermgr_createinctx(*mctxp, *actxp, timermgrp); + if (result != ISC_R_SUCCESS) + goto fail; + + return (ISC_R_SUCCESS); + + fail: + ctxs_destroy(mctxp, actxp, taskmgrp, socketmgrp, timermgrp); + + return (result); +} + +#ifdef ISC_PLATFORM_USETHREADS +static void +free_specific_context(void *arg) { + irs_context_t *context = arg; + + irs_context_destroy(&context); + + isc_thread_key_setspecific(irs_context_key, NULL); +} + +static void +thread_key_mutex_init(void) { + RUNTIME_CHECK(isc_mutex_init(&thread_key_mutex) == ISC_R_SUCCESS); +} + +static isc_result_t +thread_key_init() { + isc_result_t result; + + result = isc_once_do(&once, thread_key_mutex_init); + if (result != ISC_R_SUCCESS) + return (result); + + if (!thread_key_initialized) { + LOCK(&thread_key_mutex); + + if (!thread_key_initialized && + isc_thread_key_create(&irs_context_key, + free_specific_context) != 0) { + result = ISC_R_FAILURE; + } else + thread_key_initialized = ISC_TRUE; + + UNLOCK(&thread_key_mutex); + } + + return (result); +} +#endif /* ISC_PLATFORM_USETHREADS */ + +isc_result_t +irs_context_get(irs_context_t **contextp) { + irs_context_t *context; + isc_result_t result; + + REQUIRE(contextp != NULL && *contextp == NULL); + +#ifndef ISC_PLATFORM_USETHREADS + if (irs_g_context == NULL) { + result = irs_context_create(&irs_g_context); + if (result != ISC_R_SUCCESS) + return (result); + } + + context = irs_g_context; +#else + result = thread_key_init(); + if (result != ISC_R_SUCCESS) + return (result); + + context = isc_thread_key_getspecific(irs_context_key); + if (context == NULL) { + result = irs_context_create(&context); + if (result != ISC_R_SUCCESS) + return (result); + result = isc_thread_key_setspecific(irs_context_key, context); + if (result != ISC_R_SUCCESS) { + irs_context_destroy(&context); + return (result); + } + } +#endif /* ISC_PLATFORM_USETHREADS */ + + *contextp = context; + + return (ISC_R_SUCCESS); +} + +isc_result_t +irs_context_create(irs_context_t **contextp) { + isc_result_t result; + irs_context_t *context; + isc_appctx_t *actx = NULL; + isc_mem_t *mctx = NULL; + isc_taskmgr_t *taskmgr = NULL; + isc_socketmgr_t *socketmgr = NULL; + isc_timermgr_t *timermgr = NULL; + dns_client_t *client = NULL; + isc_sockaddrlist_t *nameservers; + irs_dnsconf_dnskeylist_t *trustedkeys; + irs_dnsconf_dnskey_t *trustedkey; + + isc_lib_register(); + result = dns_lib_init(); + if (result != ISC_R_SUCCESS) + return (result); + + result = ctxs_init(&mctx, &actx, &taskmgr, &socketmgr, &timermgr); + if (result != ISC_R_SUCCESS) + return (result); + + result = isc_app_ctxstart(actx); + if (result != ISC_R_SUCCESS) { + ctxs_destroy(&mctx, &actx, &taskmgr, &socketmgr, &timermgr); + return (result); + } + + context = isc_mem_get(mctx, sizeof(*context)); + if (context == NULL) { + ctxs_destroy(&mctx, &actx, &taskmgr, &socketmgr, &timermgr); + return (ISC_R_NOMEMORY); + } + + context->mctx = mctx; + context->actx = actx; + context->taskmgr = taskmgr; + context->socketmgr = socketmgr; + context->timermgr = timermgr; + context->resconf = NULL; + context->dnsconf = NULL; + context->task = NULL; + result = isc_task_create(taskmgr, 0, &context->task); + if (result != ISC_R_SUCCESS) + goto fail; + + /* Create a DNS client object */ + result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr, + 0, &client); + if (result != ISC_R_SUCCESS) + goto fail; + context->dnsclient = client; + + /* Read resolver configuration file */ + result = irs_resconf_load(mctx, RESOLV_CONF, &context->resconf); + if (result != ISC_R_SUCCESS) + goto fail; + /* Set nameservers */ + nameservers = irs_resconf_getnameservers(context->resconf); + result = dns_client_setservers(client, dns_rdataclass_in, NULL, + nameservers); + if (result != ISC_R_SUCCESS) + goto fail; + + /* Read advanced DNS configuration (if any) */ + result = irs_dnsconf_load(mctx, DNS_CONF, &context->dnsconf); + if (result != ISC_R_SUCCESS) + goto fail; + trustedkeys = irs_dnsconf_gettrustedkeys(context->dnsconf); + for (trustedkey = ISC_LIST_HEAD(*trustedkeys); + trustedkey != NULL; + trustedkey = ISC_LIST_NEXT(trustedkey, link)) { + result = dns_client_addtrustedkey(client, dns_rdataclass_in, + trustedkey->keyname, + trustedkey->keydatabuf); + if (result != ISC_R_SUCCESS) + goto fail; + } + + context->magic = IRS_CONTEXT_MAGIC; + *contextp = context; + + return (ISC_R_SUCCESS); + + fail: + if (context->task != NULL) + isc_task_detach(&context->task); + if (context->resconf != NULL) + irs_resconf_destroy(&context->resconf); + if (context->dnsconf != NULL) + irs_dnsconf_destroy(&context->dnsconf); + if (client != NULL) + dns_client_destroy(&client); + ctxs_destroy(NULL, &actx, &taskmgr, &socketmgr, &timermgr); + isc_mem_putanddetach(&mctx, context, sizeof(*context)); + + return (result); +} + +void +irs_context_destroy(irs_context_t **contextp) { + irs_context_t *context; + + REQUIRE(contextp != NULL); + context = *contextp; + REQUIRE(IRS_CONTEXT_VALID(context)); + + isc_task_detach(&context->task); + irs_dnsconf_destroy(&context->dnsconf); + irs_resconf_destroy(&context->resconf); + dns_client_destroy(&context->dnsclient); + + ctxs_destroy(NULL, &context->actx, &context->taskmgr, + &context->socketmgr, &context->timermgr); + + context->magic = 0; + + isc_mem_putanddetach(&context->mctx, context, sizeof(*context)); + + *contextp = NULL; + +#ifndef ISC_PLATFORM_USETHREADS + irs_g_context = NULL; +#else + (void)isc_thread_key_setspecific(irs_context_key, NULL); +#endif +} + +isc_mem_t * +irs_context_getmctx(irs_context_t *context) { + REQUIRE(IRS_CONTEXT_VALID(context)); + + return (context->mctx); +} + +isc_appctx_t * +irs_context_getappctx(irs_context_t *context) { + REQUIRE(IRS_CONTEXT_VALID(context)); + + return (context->actx); +} + +isc_taskmgr_t * +irs_context_gettaskmgr(irs_context_t *context) { + REQUIRE(IRS_CONTEXT_VALID(context)); + + return (context->taskmgr); +} + +isc_timermgr_t * +irs_context_gettimermgr(irs_context_t *context) { + REQUIRE(IRS_CONTEXT_VALID(context)); + + return (context->timermgr); +} + +isc_task_t * +irs_context_gettask(irs_context_t *context) { + REQUIRE(IRS_CONTEXT_VALID(context)); + + return (context->task); +} + +dns_client_t * +irs_context_getdnsclient(irs_context_t *context) { + REQUIRE(IRS_CONTEXT_VALID(context)); + + return (context->dnsclient); +} + +irs_resconf_t * +irs_context_getresconf(irs_context_t *context) { + REQUIRE(IRS_CONTEXT_VALID(context)); + + return (context->resconf); +} + +irs_dnsconf_t * +irs_context_getdnsconf(irs_context_t *context) { + REQUIRE(IRS_CONTEXT_VALID(context)); + + return (context->dnsconf); +} diff --git a/lib/irs/dnsconf.c b/lib/irs/dnsconf.c new file mode 100644 index 0000000..8464d6d --- /dev/null +++ b/lib/irs/dnsconf.c @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: dnsconf.c,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +/*! \file */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#define IRS_DNSCONF_MAGIC ISC_MAGIC('D', 'c', 'f', 'g') +#define IRS_DNSCONF_VALID(c) ISC_MAGIC_VALID(c, IRS_DNSCONF_MAGIC) + +/*! + * configuration data structure + */ + +struct irs_dnsconf { + unsigned int magic; + isc_mem_t *mctx; + irs_dnsconf_dnskeylist_t trusted_keylist; +}; + +static isc_result_t +configure_dnsseckeys(irs_dnsconf_t *conf, cfg_obj_t *cfgobj, + dns_rdataclass_t rdclass) +{ + isc_mem_t *mctx = conf->mctx; + const cfg_obj_t *keys = NULL; + const cfg_obj_t *key, *keylist; + dns_fixedname_t fkeyname; + dns_name_t *keyname_base, *keyname; + const cfg_listelt_t *element, *element2; + isc_result_t result; + isc_uint32_t flags, proto, alg; + const char *keystr, *keynamestr; + unsigned char keydata[4096]; + isc_buffer_t keydatabuf_base, *keydatabuf; + dns_rdata_dnskey_t keystruct; + unsigned char rrdata[4096]; + isc_buffer_t rrdatabuf; + isc_region_t r; + isc_buffer_t namebuf; + irs_dnsconf_dnskey_t *keyent; + + cfg_map_get(cfgobj, "trusted-keys", &keys); + if (keys == NULL) + return (ISC_R_SUCCESS); + + for (element = cfg_list_first(keys); + element != NULL; + element = cfg_list_next(element)) { + keylist = cfg_listelt_value(element); + for (element2 = cfg_list_first(keylist); + element2 != NULL; + element2 = cfg_list_next(element2)) + { + keydatabuf = NULL; + keyname = NULL; + + key = cfg_listelt_value(element2); + + flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags")); + proto = cfg_obj_asuint32(cfg_tuple_get(key, + "protocol")); + alg = cfg_obj_asuint32(cfg_tuple_get(key, + "algorithm")); + keynamestr = cfg_obj_asstring(cfg_tuple_get(key, + "name")); + + keystruct.common.rdclass = rdclass; + keystruct.common.rdtype = dns_rdatatype_dnskey; + keystruct.mctx = NULL; + ISC_LINK_INIT(&keystruct.common, link); + + if (flags > 0xffff) + return (ISC_R_RANGE); + if (proto > 0xff) + return (ISC_R_RANGE); + if (alg > 0xff) + return (ISC_R_RANGE); + keystruct.flags = (isc_uint16_t)flags; + keystruct.protocol = (isc_uint8_t)proto; + keystruct.algorithm = (isc_uint8_t)alg; + + isc_buffer_init(&keydatabuf_base, keydata, + sizeof(keydata)); + isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); + + /* Configure key value */ + keystr = cfg_obj_asstring(cfg_tuple_get(key, "key")); + result = isc_base64_decodestring(keystr, + &keydatabuf_base); + if (result != ISC_R_SUCCESS) + return (result); + isc_buffer_usedregion(&keydatabuf_base, &r); + keystruct.datalen = r.length; + keystruct.data = r.base; + + result = dns_rdata_fromstruct(NULL, + keystruct.common.rdclass, + keystruct.common.rdtype, + &keystruct, &rrdatabuf); + if (result != ISC_R_SUCCESS) + return (result); + isc_buffer_usedregion(&rrdatabuf, &r); + result = isc_buffer_allocate(mctx, &keydatabuf, + r.length); + if (result != ISC_R_SUCCESS) + return (result); + result = isc_buffer_copyregion(keydatabuf, &r); + if (result != ISC_R_SUCCESS) + goto cleanup; + + /* Configure key name */ + dns_fixedname_init(&fkeyname); + keyname_base = dns_fixedname_name(&fkeyname); + isc_buffer_init(&namebuf, keynamestr, + strlen(keynamestr)); + isc_buffer_add(&namebuf, strlen(keynamestr)); + result = dns_name_fromtext(keyname_base, &namebuf, + dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) + return (result); + keyname = isc_mem_get(mctx, sizeof(*keyname)); + if (keyname == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + dns_name_init(keyname, NULL); + result = dns_name_dup(keyname_base, mctx, keyname); + if (result != ISC_R_SUCCESS) + goto cleanup; + + /* Add the key data to the list */ + keyent = isc_mem_get(mctx, sizeof(*keyent)); + if (keyent == NULL) { + dns_name_free(keyname, mctx); + result = ISC_R_NOMEMORY; + goto cleanup; + } + keyent->keyname = keyname; + keyent->keydatabuf = keydatabuf; + + ISC_LIST_APPEND(conf->trusted_keylist, keyent, link); + } + } + + return (ISC_R_SUCCESS); + + cleanup: + if (keydatabuf != NULL) + isc_buffer_free(&keydatabuf); + if (keyname != NULL) + isc_mem_put(mctx, keyname, sizeof(*keyname)); + + return (result); +} + +isc_result_t +irs_dnsconf_load(isc_mem_t *mctx, const char *filename, irs_dnsconf_t **confp) +{ + irs_dnsconf_t *conf; + cfg_parser_t *parser = NULL; + cfg_obj_t *cfgobj = NULL; + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(confp != NULL && *confp == NULL); + + conf = isc_mem_get(mctx, sizeof(*conf)); + if (conf == NULL) + return (ISC_R_NOMEMORY); + + conf->mctx = mctx; + ISC_LIST_INIT(conf->trusted_keylist); + + /* + * If the specified file does not exist, we'll simply with an empty + * configuration. + */ + if (!isc_file_exists(filename)) + goto cleanup; + + result = cfg_parser_create(mctx, NULL, &parser); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = cfg_parse_file(parser, filename, &cfg_type_dnsconf, + &cfgobj); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = configure_dnsseckeys(conf, cfgobj, dns_rdataclass_in); + + cleanup: + if (parser != NULL) { + if (cfgobj != NULL) + cfg_obj_destroy(parser, &cfgobj); + cfg_parser_destroy(&parser); + } + + conf->magic = IRS_DNSCONF_MAGIC; + + if (result == ISC_R_SUCCESS) + *confp = conf; + else + irs_dnsconf_destroy(&conf); + + return (result); +} + +void +irs_dnsconf_destroy(irs_dnsconf_t **confp) { + irs_dnsconf_t *conf; + irs_dnsconf_dnskey_t *keyent; + + REQUIRE(confp != NULL); + conf = *confp; + REQUIRE(IRS_DNSCONF_VALID(conf)); + + while ((keyent = ISC_LIST_HEAD(conf->trusted_keylist)) != NULL) { + ISC_LIST_UNLINK(conf->trusted_keylist, keyent, link); + + isc_buffer_free(&keyent->keydatabuf); + dns_name_free(keyent->keyname, conf->mctx); + isc_mem_put(conf->mctx, keyent->keyname, sizeof(dns_name_t)); + isc_mem_put(conf->mctx, keyent, sizeof(*keyent)); + } + + isc_mem_put(conf->mctx, conf, sizeof(*conf)); + + *confp = NULL; +} + +irs_dnsconf_dnskeylist_t * +irs_dnsconf_gettrustedkeys(irs_dnsconf_t *conf) { + REQUIRE(IRS_DNSCONF_VALID(conf)); + + return (&conf->trusted_keylist); +} diff --git a/lib/irs/gai_strerror.c b/lib/irs/gai_strerror.c new file mode 100644 index 0000000..aa021ef --- /dev/null +++ b/lib/irs/gai_strerror.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: gai_strerror.c,v 1.5 2009-09-02 23:48:02 tbox Exp $ */ + +/*! \file gai_strerror.c + * gai_strerror() returns an error message corresponding to an + * error code returned by getaddrinfo() and getnameinfo(). The following error + * codes and their meaning are defined in + * \link netdb.h include/irs/netdb.h.\endlink + * This implementation is almost an exact copy of lwres/gai_sterror.c except + * that it catches up the latest API standard, RFC3493. + * + * \li #EAI_ADDRFAMILY address family for hostname not supported + * \li #EAI_AGAIN temporary failure in name resolution + * \li #EAI_BADFLAGS invalid value for ai_flags + * \li #EAI_FAIL non-recoverable failure in name resolution + * \li #EAI_FAMILY ai_family not supported + * \li #EAI_MEMORY memory allocation failure + * \li #EAI_NODATA no address associated with hostname (obsoleted in RFC3493) + * \li #EAI_NONAME hostname nor servname provided, or not known + * \li #EAI_SERVICE servname not supported for ai_socktype + * \li #EAI_SOCKTYPE ai_socktype not supported + * \li #EAI_SYSTEM system error returned in errno + * \li #EAI_BADHINTS Invalid value for hints (non-standard) + * \li #EAI_PROTOCOL Resolved protocol is unknown (non-standard) + * \li #EAI_OVERFLOW Argument buffer overflow + * \li #EAI_INSECUREDATA Insecure Data (experimental) + * + * The message invalid error code is returned if ecode is out of range. + * + * ai_flags, ai_family and ai_socktype are elements of the struct + * addrinfo used by lwres_getaddrinfo(). + * + * \section gai_strerror_see See Also + * + * strerror(), getaddrinfo(), getnameinfo(), RFC3493. + */ +#include + +#include + +/*% Text of error messages. */ +static const char *gai_messages[] = { + "no error", + "address family for hostname not supported", + "temporary failure in name resolution", + "invalid value for ai_flags", + "non-recoverable failure in name resolution", + "ai_family not supported", + "memory allocation failure", + "no address associated with hostname", + "hostname nor servname provided, or not known", + "servname not supported for ai_socktype", + "ai_socktype not supported", + "system error returned in errno", + "bad hints", + "bad protocol", + "argument buffer overflow", + "insecure data provided" +}; + +/*% + * Returns an error message corresponding to an error code returned by + * getaddrinfo() and getnameinfo() + */ +IRS_GAISTRERROR_RETURN_T +gai_strerror(int ecode) { + union { + const char *const_ptr; + char *deconst_ptr; + } ptr; + + if ((ecode < 0) || + (ecode >= (int)(sizeof(gai_messages)/sizeof(*gai_messages)))) + ptr.const_ptr = "invalid error code"; + else + ptr.const_ptr = gai_messages[ecode]; + return (ptr.deconst_ptr); +} diff --git a/lib/irs/getaddrinfo.c b/lib/irs/getaddrinfo.c new file mode 100644 index 0000000..e7075da --- /dev/null +++ b/lib/irs/getaddrinfo.c @@ -0,0 +1,1295 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: getaddrinfo.c,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +/*! \file */ + +/** + * getaddrinfo() is used to get a list of IP addresses and port + * numbers for host hostname and service servname as defined in RFC3493. + * hostname and servname are pointers to null-terminated strings + * or NULL. hostname is either a host name or a numeric host address + * string: a dotted decimal IPv4 address or an IPv6 address. servname is + * either a decimal port number or a service name as listed in + * /etc/services. + * + * If the operating system does not provide a struct addrinfo, the + * following structure is used: + * + * \code + * struct addrinfo { + * int ai_flags; // AI_PASSIVE, AI_CANONNAME + * int ai_family; // PF_xxx + * int ai_socktype; // SOCK_xxx + * int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6 + * size_t ai_addrlen; // length of ai_addr + * char *ai_canonname; // canonical name for hostname + * struct sockaddr *ai_addr; // binary address + * struct addrinfo *ai_next; // next structure in linked list + * }; + * \endcode + * + * + * hints is an optional pointer to a struct addrinfo. This structure can + * be used to provide hints concerning the type of socket that the caller + * supports or wishes to use. The caller can supply the following + * structure elements in *hints: + * + *
    + *
  • ai_family: + * The protocol family that should be used. When ai_family is set + * to PF_UNSPEC, it means the caller will accept any protocol + * family supported by the operating system.
  • + * + *
  • ai_socktype: + * denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or + * SOCK_RAW -- that is wanted. When ai_socktype is zero the caller + * will accept any socket type.
  • + * + *
  • ai_protocol: + * indicates which transport protocol is wanted: IPPROTO_UDP or + * IPPROTO_TCP. If ai_protocol is zero the caller will accept any + * protocol.
  • + * + *
  • ai_flags: + * Flag bits. If the AI_CANONNAME bit is set, a successful call to + * getaddrinfo() will return a null-terminated string + * containing the canonical name of the specified hostname in + * ai_canonname of the first addrinfo structure returned. Setting + * the AI_PASSIVE bit indicates that the returned socket address + * structure is intended for used in a call to bind(2). In this + * case, if the hostname argument is a NULL pointer, then the IP + * address portion of the socket address structure will be set to + * INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6 + * address.

    + * + * When ai_flags does not set the AI_PASSIVE bit, the returned + * socket address structure will be ready for use in a call to + * connect(2) for a connection-oriented protocol or connect(2), + * sendto(2), or sendmsg(2) if a connectionless protocol was + * chosen. The IP address portion of the socket address structure + * will be set to the loopback address if hostname is a NULL + * pointer and AI_PASSIVE is not set in ai_flags.

    + * + * If ai_flags is set to AI_NUMERICHOST it indicates that hostname + * should be treated as a numeric string defining an IPv4 or IPv6 + * address and no name resolution should be attempted. + *
+ * + * All other elements of the struct addrinfo passed via hints must be + * zero. + * + * A hints of NULL is treated as if the caller provided a struct addrinfo + * initialized to zero with ai_familyset to PF_UNSPEC. + * + * After a successful call to getaddrinfo(), *res is a pointer to a + * linked list of one or more addrinfo structures. Each struct addrinfo + * in this list cn be processed by following the ai_next pointer, until a + * NULL pointer is encountered. The three members ai_family, ai_socktype, + * and ai_protocol in each returned addrinfo structure contain the + * corresponding arguments for a call to socket(2). For each addrinfo + * structure in the list, the ai_addr member points to a filled-in socket + * address structure of length ai_addrlen. + * + * All of the information returned by getaddrinfo() is dynamically + * allocated: the addrinfo structures, and the socket address structures + * and canonical host name strings pointed to by the addrinfostructures. + * Memory allocated for the dynamically allocated structures created by a + * successful call to getaddrinfo() is released by freeaddrinfo(). + * ai is a pointer to a struct addrinfo created by a call to getaddrinfo(). + * + * \section irsreturn RETURN VALUES + * + * getaddrinfo() returns zero on success or one of the error codes + * listed in gai_strerror() if an error occurs. If both hostname and + * servname are NULL getaddrinfo() returns #EAI_NONAME. + * + * \section irssee SEE ALSO + * + * getaddrinfo(), freeaddrinfo(), + * gai_strerror(), RFC3493, getservbyname(3), connect(2), + * sendto(2), sendmsg(2), socket(2). + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define SA(addr) ((struct sockaddr *)(addr)) +#define SIN(addr) ((struct sockaddr_in *)(addr)) +#define SIN6(addr) ((struct sockaddr_in6 *)(addr)) +#define SLOCAL(addr) ((struct sockaddr_un *)(addr)) + +/*! \struct addrinfo + */ +static struct addrinfo + *ai_concat(struct addrinfo *ai1, struct addrinfo *ai2), + *ai_reverse(struct addrinfo *oai), + *ai_clone(struct addrinfo *oai, int family), + *ai_alloc(int family, int addrlen); +#ifdef AF_LOCAL +static int get_local(const char *name, int socktype, struct addrinfo **res); +#endif + +static int +resolve_name(int family, const char *hostname, int flags, + struct addrinfo **aip, int socktype, int port); + +static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip, + int socktype, int port); +static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip, + int socktype, int port); +static void set_order(int, int (**)(const char *, int, struct addrinfo **, + int, int)); + +#define FOUND_IPV4 0x1 +#define FOUND_IPV6 0x2 +#define FOUND_MAX 2 + +#define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST) +/*% + * Get a list of IP addresses and port numbers for host hostname and + * service servname. + */ +int +getaddrinfo(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + struct servent *sp; + const char *proto; + int family, socktype, flags, protocol; + struct addrinfo *ai, *ai_list; + int err = 0; + int port, i; + int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **, + int, int); + + if (hostname == NULL && servname == NULL) + return (EAI_NONAME); + + proto = NULL; + if (hints != NULL) { + if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0) + return (EAI_BADFLAGS); + if (hints->ai_addrlen || hints->ai_canonname || + hints->ai_addr || hints->ai_next) { + errno = EINVAL; + return (EAI_SYSTEM); + } + family = hints->ai_family; + socktype = hints->ai_socktype; + protocol = hints->ai_protocol; + flags = hints->ai_flags; + switch (family) { + case AF_UNSPEC: + switch (hints->ai_socktype) { + case SOCK_STREAM: + proto = "tcp"; + break; + case SOCK_DGRAM: + proto = "udp"; + break; + } + break; + case AF_INET: + case AF_INET6: + switch (hints->ai_socktype) { + case 0: + break; + case SOCK_STREAM: + proto = "tcp"; + break; + case SOCK_DGRAM: + proto = "udp"; + break; + case SOCK_RAW: + break; + default: + return (EAI_SOCKTYPE); + } + break; +#ifdef AF_LOCAL + case AF_LOCAL: + switch (hints->ai_socktype) { + case 0: + break; + case SOCK_STREAM: + break; + case SOCK_DGRAM: + break; + default: + return (EAI_SOCKTYPE); + } + break; +#endif + default: + return (EAI_FAMILY); + } + } else { + protocol = 0; + family = 0; + socktype = 0; + flags = 0; + } + +#ifdef AF_LOCAL + /*! + * First, deal with AF_LOCAL. If the family was not set, + * then assume AF_LOCAL if the first character of the + * hostname/servname is '/'. + */ + + if (hostname != NULL && + (family == AF_LOCAL || (family == 0 && *hostname == '/'))) + return (get_local(hostname, socktype, res)); + + if (servname != NULL && + (family == AF_LOCAL || (family == 0 && *servname == '/'))) + return (get_local(servname, socktype, res)); +#endif + + /* + * Ok, only AF_INET and AF_INET6 left. + */ + ai_list = NULL; + + /* + * First, look up the service name (port) if it was + * requested. If the socket type wasn't specified, then + * try and figure it out. + */ + if (servname != NULL) { + char *e; + + port = strtol(servname, &e, 10); + if (*e == '\0') { + if (socktype == 0) + return (EAI_SOCKTYPE); + if (port < 0 || port > 65535) + return (EAI_SERVICE); + port = htons((unsigned short) port); + } else { + sp = getservbyname(servname, proto); + if (sp == NULL) + return (EAI_SERVICE); + port = sp->s_port; + if (socktype == 0) { + if (strcmp(sp->s_proto, "tcp") == 0) + socktype = SOCK_STREAM; + else if (strcmp(sp->s_proto, "udp") == 0) + socktype = SOCK_DGRAM; + } + } + } else + port = 0; + + /* + * Next, deal with just a service name, and no hostname. + * (we verified that one of them was non-null up above). + */ + if (hostname == NULL && (flags & AI_PASSIVE) != 0) { + if (family == AF_INET || family == 0) { + ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in)); + if (ai == NULL) + return (EAI_MEMORY); + ai->ai_socktype = socktype; + ai->ai_protocol = protocol; + SIN(ai->ai_addr)->sin_port = port; + ai->ai_next = ai_list; + ai_list = ai; + } + + if (family == AF_INET6 || family == 0) { + ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6)); + if (ai == NULL) { + freeaddrinfo(ai_list); + return (EAI_MEMORY); + } + ai->ai_socktype = socktype; + ai->ai_protocol = protocol; + SIN6(ai->ai_addr)->sin6_port = port; + ai->ai_next = ai_list; + ai_list = ai; + } + + *res = ai_list; + return (0); + } + + /* + * If the family isn't specified or AI_NUMERICHOST specified, check + * first to see if it is a numeric address. + * Though the gethostbyname2() routine will recognize numeric addresses, + * it will only recognize the format that it is being called for. Thus, + * a numeric AF_INET address will be treated by the AF_INET6 call as + * a domain name, and vice versa. Checking for both numerics here + * avoids that. + */ + if (hostname != NULL && + (family == 0 || (flags & AI_NUMERICHOST) != 0)) { + char abuf[sizeof(struct in6_addr)]; + char nbuf[NI_MAXHOST]; + int addrsize, addroff; +#ifdef IRS_HAVE_SIN6_SCOPE_ID + char *p, *ep; + char ntmp[NI_MAXHOST]; + isc_uint32_t scopeid; +#endif + +#ifdef IRS_HAVE_SIN6_SCOPE_ID + /* + * Scope identifier portion. + */ + ntmp[0] = '\0'; + if (strchr(hostname, '%') != NULL) { + strncpy(ntmp, hostname, sizeof(ntmp) - 1); + ntmp[sizeof(ntmp) - 1] = '\0'; + p = strchr(ntmp, '%'); + ep = NULL; + + /* + * Vendors may want to support non-numeric + * scopeid around here. + */ + + if (p != NULL) + scopeid = (isc_uint32_t)strtoul(p + 1, + &ep, 10); + if (p != NULL && ep != NULL && ep[0] == '\0') + *p = '\0'; + else { + ntmp[0] = '\0'; + scopeid = 0; + } + } else + scopeid = 0; +#endif + + if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf) + == 1) { + if (family == AF_INET6) { + /* + * Convert to a V4 mapped address. + */ + struct in6_addr *a6 = (struct in6_addr *)abuf; + memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4); + memset(&a6->s6_addr[10], 0xff, 2); + memset(&a6->s6_addr[0], 0, 10); + goto inet6_addr; + } + addrsize = sizeof(struct in_addr); + addroff = (char *)(&SIN(0)->sin_addr) - (char *)0; + family = AF_INET; + goto common; +#ifdef IRS_HAVE_SIN6_SCOPE_ID + } else if (ntmp[0] != '\0' && + inet_pton(AF_INET6, ntmp, abuf) == 1) { + if (family && family != AF_INET6) + return (EAI_NONAME); + addrsize = sizeof(struct in6_addr); + addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; + family = AF_INET6; + goto common; +#endif + } else if (inet_pton(AF_INET6, hostname, abuf) == 1) { + if (family != 0 && family != AF_INET6) + return (EAI_NONAME); + inet6_addr: + addrsize = sizeof(struct in6_addr); + addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; + family = AF_INET6; + + common: + ai = ai_alloc(family, + ((family == AF_INET6) ? + sizeof(struct sockaddr_in6) : + sizeof(struct sockaddr_in))); + if (ai == NULL) + return (EAI_MEMORY); + ai_list = ai; + ai->ai_socktype = socktype; + SIN(ai->ai_addr)->sin_port = port; + memcpy((char *)ai->ai_addr + addroff, abuf, addrsize); + if ((flags & AI_CANONNAME) != 0) { +#ifdef IRS_HAVE_SIN6_SCOPE_ID + if (ai->ai_family == AF_INET6) + SIN6(ai->ai_addr)->sin6_scope_id = + scopeid; +#endif + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, + nbuf, sizeof(nbuf), NULL, 0, + NI_NUMERICHOST) == 0) { + ai->ai_canonname = strdup(nbuf); + if (ai->ai_canonname == NULL) { + freeaddrinfo(ai); + return (EAI_MEMORY); + } + } else { + /* XXX raise error? */ + ai->ai_canonname = NULL; + } + } + goto done; + } else if ((flags & AI_NUMERICHOST) != 0) { + return (EAI_NONAME); + } + } + + if (hostname == NULL && (flags & AI_PASSIVE) == 0) { + set_order(family, net_order); + for (i = 0; i < FOUND_MAX; i++) { + if (net_order[i] == NULL) + break; + err = (net_order[i])(hostname, flags, &ai_list, + socktype, port); + if (err != 0) { + if (ai_list != NULL) + freeaddrinfo(ai_list); + break; + } + } + } else + err = resolve_name(family, hostname, flags, &ai_list, + socktype, port); + + if (ai_list == NULL) { + if (err == 0) + err = EAI_NONAME; + return (err); + } + +done: + ai_list = ai_reverse(ai_list); + + *res = ai_list; + return (0); +} + +typedef struct gai_restrans { + dns_clientrestrans_t *xid; + isc_boolean_t is_inprogress; + int error; + struct addrinfo ai_sentinel; + struct gai_resstate *resstate; +} gai_restrans_t; + +typedef struct gai_resstate { + isc_mem_t *mctx; + struct gai_statehead *head; + dns_fixedname_t fixedname; + dns_name_t *qname; + gai_restrans_t *trans4; + gai_restrans_t *trans6; + ISC_LINK(struct gai_resstate) link; +} gai_resstate_t; + +typedef struct gai_statehead { + int ai_family; + int ai_flags; + int ai_socktype; + int ai_port; + isc_appctx_t *actx; + dns_client_t *dnsclient; + ISC_LIST(struct gai_resstate) resstates; + unsigned int activestates; +} gai_statehead_t; + +static isc_result_t +make_resstate(isc_mem_t *mctx, gai_statehead_t *head, const char *hostname, + const char *domain, gai_resstate_t **statep) +{ + isc_result_t result; + gai_resstate_t *state; + dns_fixedname_t fixeddomain; + dns_name_t *qdomain; + size_t namelen; + isc_buffer_t b; + isc_boolean_t need_v4 = ISC_FALSE; + isc_boolean_t need_v6 = ISC_FALSE; + + state = isc_mem_get(mctx, sizeof(*state)); + if (state == NULL) + return (ISC_R_NOMEMORY); + + /* Construct base domain name */ + namelen = strlen(domain); + isc_buffer_init(&b, domain, namelen); + isc_buffer_add(&b, namelen); + dns_fixedname_init(&fixeddomain); + qdomain = dns_fixedname_name(&fixeddomain); + result = dns_name_fromtext(qdomain, &b, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, state, sizeof(*state)); + return (result); + } + + /* Construct query name */ + namelen = strlen(hostname); + isc_buffer_init(&b, hostname, namelen); + isc_buffer_add(&b, namelen); + dns_fixedname_init(&state->fixedname); + state->qname = dns_fixedname_name(&state->fixedname); + result = dns_name_fromtext(state->qname, &b, qdomain, 0, NULL); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, state, sizeof(*state)); + return (result); + } + + if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET) + need_v4 = ISC_TRUE; + if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET6) + need_v6 = ISC_TRUE; + + state->trans6 = NULL; + state->trans4 = NULL; + if (need_v4) { + state->trans4 = isc_mem_get(mctx, sizeof(gai_restrans_t)); + if (state->trans4 == NULL) { + isc_mem_put(mctx, state, sizeof(*state)); + return (ISC_R_NOMEMORY); + } + state->trans4->error = 0; + state->trans4->xid = NULL; + state->trans4->resstate = state; + state->trans4->is_inprogress = ISC_TRUE; + state->trans4->ai_sentinel.ai_next = NULL; + } + if (need_v6) { + state->trans6 = isc_mem_get(mctx, sizeof(gai_restrans_t)); + if (state->trans6 == NULL) { + if (state->trans4 != NULL) + isc_mem_put(mctx, state->trans4, + sizeof(*state->trans4)); + isc_mem_put(mctx, state, sizeof(*state)); + return (ISC_R_NOMEMORY); + } + state->trans6->error = 0; + state->trans6->xid = NULL; + state->trans6->resstate = state; + state->trans6->is_inprogress = ISC_TRUE; + state->trans6->ai_sentinel.ai_next = NULL; + } + + state->mctx = mctx; + state->head = head; + ISC_LINK_INIT(state, link); + + *statep = state; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +make_resstates(isc_mem_t *mctx, const char *hostname, gai_statehead_t *head, + irs_resconf_t *resconf) +{ + isc_result_t result; + irs_resconf_searchlist_t *searchlist; + irs_resconf_search_t *searchent; + gai_resstate_t *resstate, *resstate0; + + resstate0 = NULL; + result = make_resstate(mctx, head, hostname, ".", &resstate0); + if (result != ISC_R_SUCCESS) + return (result); + + searchlist = irs_resconf_getsearchlist(resconf); + for (searchent = ISC_LIST_HEAD(*searchlist); searchent != NULL; + searchent = ISC_LIST_NEXT(searchent, link)) { + resstate = NULL; + result = make_resstate(mctx, head, hostname, + (const char *)searchent->domain, + &resstate); + if (result != ISC_R_SUCCESS) + break; + + ISC_LIST_APPEND(head->resstates, resstate, link); + head->activestates++; + } + + /* + * Insert the original hostname either at the head or the tail of the + * state list, depending on the number of labels contained in the + * original name and the 'ndots' configuration parameter. + */ + if (dns_name_countlabels(resstate0->qname) > + irs_resconf_getndots(resconf) + 1) { + ISC_LIST_PREPEND(head->resstates, resstate0, link); + } else + ISC_LIST_APPEND(head->resstates, resstate0, link); + head->activestates++; + + if (result != ISC_R_SUCCESS) { + while ((resstate = ISC_LIST_HEAD(head->resstates)) != NULL) { + ISC_LIST_UNLINK(head->resstates, resstate, link); + if (resstate->trans4 != NULL) { + isc_mem_put(mctx, resstate->trans4, + sizeof(*resstate->trans4)); + } + if (resstate->trans6 != NULL) { + isc_mem_put(mctx, resstate->trans6, + sizeof(*resstate->trans6)); + } + + isc_mem_put(mctx, resstate, sizeof(*resstate)); + } + } + + return (result); +} + +static void +process_answer(isc_task_t *task, isc_event_t *event) { + int error = 0, family; + gai_restrans_t *trans = event->ev_arg; + gai_resstate_t *resstate; + dns_clientresevent_t *rev = (dns_clientresevent_t *)event; + dns_rdatatype_t qtype; + dns_name_t *name; + + REQUIRE(trans != NULL); + resstate = trans->resstate; + REQUIRE(resstate != NULL); + REQUIRE(task != NULL); + + if (trans == resstate->trans4) { + family = AF_INET; + qtype = dns_rdatatype_a; + } else { + INSIST(trans == resstate->trans6); + family = AF_INET6; + qtype = dns_rdatatype_aaaa; + } + + INSIST(trans->is_inprogress); + trans->is_inprogress = ISC_FALSE; + + switch (rev->result) { + case ISC_R_SUCCESS: + case DNS_R_NCACHENXDOMAIN: /* treat this as a fatal error? */ + case DNS_R_NCACHENXRRSET: + break; + default: + switch (rev->vresult) { + case DNS_R_SIGINVALID: + case DNS_R_SIGEXPIRED: + case DNS_R_SIGFUTURE: + case DNS_R_KEYUNAUTHORIZED: + case DNS_R_MUSTBESECURE: + case DNS_R_COVERINGNSEC: + case DNS_R_NOTAUTHORITATIVE: + case DNS_R_NOVALIDKEY: + case DNS_R_NOVALIDDS: + case DNS_R_NOVALIDSIG: + error = EAI_INSECUREDATA; + break; + default: + error = EAI_FAIL; + } + goto done; + } + + /* Parse the response and construct the addrinfo chain */ + for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; + name = ISC_LIST_NEXT(name, link)) { + isc_result_t result; + dns_rdataset_t *rdataset; + isc_buffer_t b; + isc_region_t r; + char t[1024]; + + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + if (!dns_rdataset_isassociated(rdataset)) + continue; + if (rdataset->type != qtype) + continue; + + if ((resstate->head->ai_flags & AI_CANONNAME) != 0) { + isc_buffer_init(&b, t, sizeof(t)); + result = dns_name_totext(name, ISC_TRUE, &b); + if (result != ISC_R_SUCCESS) { + error = EAI_FAIL; + goto done; + } + isc_buffer_putuint8(&b, '\0'); + isc_buffer_usedregion(&b, &r); + } + + for (result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(rdataset)) { + struct addrinfo *ai; + dns_rdata_t rdata; + dns_rdata_in_a_t rdata_a; + dns_rdata_in_aaaa_t rdata_aaaa; + + ai = ai_alloc(family, + ((family == AF_INET6) ? + sizeof(struct sockaddr_in6) : + sizeof(struct sockaddr_in))); + if (ai == NULL) { + error = EAI_MEMORY; + goto done; + } + ai->ai_socktype = resstate->head->ai_socktype; + ai->ai_next = trans->ai_sentinel.ai_next; + trans->ai_sentinel.ai_next = ai; + + /* + * Set AF-specific parameters + * (IPv4/v6 address/port) + */ + dns_rdata_init(&rdata); + switch (family) { + case AF_INET: + dns_rdataset_current(rdataset, &rdata); + dns_rdata_tostruct(&rdata, &rdata_a, + NULL); + + SIN(ai->ai_addr)->sin_port = + resstate->head->ai_port; + memcpy(&SIN(ai->ai_addr)->sin_addr, + &rdata_a.in_addr, 4); + dns_rdata_freestruct(&rdata_a); + break; + case AF_INET6: + dns_rdataset_current(rdataset, &rdata); + dns_rdata_tostruct(&rdata, &rdata_aaaa, + NULL); + SIN6(ai->ai_addr)->sin6_port = + resstate->head->ai_port; + memcpy(&SIN6(ai->ai_addr)->sin6_addr, + &rdata_aaaa.in6_addr, 16); + dns_rdata_freestruct(&rdata_aaaa); + break; + } + + if ((resstate->head->ai_flags & AI_CANONNAME) + != 0) { + ai->ai_canonname = + strdup((const char *)r.base); + if (ai->ai_canonname == NULL) { + error = EAI_MEMORY; + goto done; + } + } + } + } + } + + done: + dns_client_freeresanswer(resstate->head->dnsclient, &rev->answerlist); + dns_client_destroyrestrans(&trans->xid); + + isc_event_free(&event); + + /* Make sure that error == 0 iff we have a non-empty list */ + if (error == 0) { + if (trans->ai_sentinel.ai_next == NULL) + error = EAI_NONAME; + } else { + if (trans->ai_sentinel.ai_next != NULL) { + freeaddrinfo(trans->ai_sentinel.ai_next); + trans->ai_sentinel.ai_next = NULL; + } + } + trans->error = error; + + /* Check whether we are done */ + if ((resstate->trans4 == NULL || !resstate->trans4->is_inprogress) && + (resstate->trans6 == NULL || !resstate->trans6->is_inprogress)) { + /* + * We're done for this state. If there is no other outstanding + * state, we can exit. + */ + resstate->head->activestates--; + if (resstate->head->activestates == 0) { + isc_app_ctxsuspend(resstate->head->actx); + return; + } + + /* + * There are outstanding states, but if we are at the head + * of the state list (i.e., at the highest search priority) + * and have any answer, we can stop now by canceling the + * others. + */ + if (resstate == ISC_LIST_HEAD(resstate->head->resstates)) { + if ((resstate->trans4 != NULL && + resstate->trans4->ai_sentinel.ai_next != NULL) || + (resstate->trans6 != NULL && + resstate->trans6->ai_sentinel.ai_next != NULL)) { + gai_resstate_t *rest; + + for (rest = ISC_LIST_NEXT(resstate, link); + rest != NULL; + rest = ISC_LIST_NEXT(rest, link)) { + if (rest->trans4 != NULL && + rest->trans4->xid != NULL) + dns_client_cancelresolve( + rest->trans4->xid); + if (rest->trans6 != NULL && + rest->trans6->xid != NULL) + dns_client_cancelresolve( + rest->trans6->xid); + } + } else { + /* + * This search fails, so we move to the tail + * of the list so that the next entry will + * have the highest priority. + */ + ISC_LIST_UNLINK(resstate->head->resstates, + resstate, link); + ISC_LIST_APPEND(resstate->head->resstates, + resstate, link); + } + } + } +} + +static int +resolve_name(int family, const char *hostname, int flags, + struct addrinfo **aip, int socktype, int port) +{ + isc_result_t result; + irs_context_t *irsctx; + irs_resconf_t *conf; + isc_mem_t *mctx; + isc_appctx_t *actx; + isc_task_t *task; + int terror = 0; + int error = 0; + dns_client_t *client; + gai_resstate_t *resstate; + gai_statehead_t head; + isc_boolean_t all_fail = ISC_TRUE; + + /* get IRS context and the associated parameters */ + irsctx = NULL; + result = irs_context_get(&irsctx); + if (result != ISC_R_SUCCESS) + return (EAI_FAIL); + actx = irs_context_getappctx(irsctx); + + mctx = irs_context_getmctx(irsctx); + task = irs_context_gettask(irsctx); + conf = irs_context_getresconf(irsctx); + client = irs_context_getdnsclient(irsctx); + + /* construct resolution states */ + head.activestates = 0; + head.ai_family = family; + head.ai_socktype = socktype; + head.ai_flags = flags; + head.ai_port = port; + head.actx = actx; + head.dnsclient = client; + ISC_LIST_INIT(head.resstates); + result = make_resstates(mctx, hostname, &head, conf); + if (result != ISC_R_SUCCESS) + return (EAI_FAIL); + + for (resstate = ISC_LIST_HEAD(head.resstates); + resstate != NULL; resstate = ISC_LIST_NEXT(resstate, link)) { + if (resstate->trans4 != NULL) { + result = dns_client_startresolve(client, + resstate->qname, + dns_rdataclass_in, + dns_rdatatype_a, + 0, task, + process_answer, + resstate->trans4, + &resstate->trans4->xid); + if (result == ISC_R_SUCCESS) { + resstate->trans4->is_inprogress = ISC_TRUE; + all_fail = ISC_FALSE; + } else + resstate->trans4->is_inprogress = ISC_FALSE; + } + if (resstate->trans6 != NULL) { + result = dns_client_startresolve(client, + resstate->qname, + dns_rdataclass_in, + dns_rdatatype_aaaa, + 0, task, + process_answer, + resstate->trans6, + &resstate->trans6->xid); + if (result == ISC_R_SUCCESS) { + resstate->trans6->is_inprogress = ISC_TRUE; + all_fail = ISC_FALSE; + } else + resstate->trans6->is_inprogress= ISC_FALSE; + } + } + if (!all_fail) { + /* Start all the events */ + isc_app_ctxrun(actx); + } else + error = EAI_FAIL; + + /* Cleanup */ + while ((resstate = ISC_LIST_HEAD(head.resstates)) != NULL) { + int terror4 = 0, terror6 = 0; + + ISC_LIST_UNLINK(head.resstates, resstate, link); + + if (*aip == NULL) { + struct addrinfo *sentinel4 = NULL; + struct addrinfo *sentinel6 = NULL; + + if (resstate->trans4 != NULL) { + sentinel4 = + resstate->trans4->ai_sentinel.ai_next; + resstate->trans4->ai_sentinel.ai_next = NULL; + } + if (resstate->trans6 != NULL) { + sentinel6 = + resstate->trans6->ai_sentinel.ai_next; + resstate->trans6->ai_sentinel.ai_next = NULL; + } + *aip = ai_concat(sentinel4, sentinel6); + } + + if (resstate->trans4 != NULL) { + INSIST(resstate->trans4->xid == NULL); + terror4 = resstate->trans4->error; + isc_mem_put(mctx, resstate->trans4, + sizeof(*resstate->trans4)); + } + if (resstate->trans6 != NULL) { + INSIST(resstate->trans6->xid == NULL); + terror6 = resstate->trans6->error; + isc_mem_put(mctx, resstate->trans6, + sizeof(*resstate->trans6)); + } + + /* + * If the entire lookup fails, we need to choose an appropriate + * error code from individual codes. We'll try to provide as + * specific a code as possible. In general, we are going to + * find an error code other than EAI_NONAME (which is too + * generic and may actually not be problematic in some cases). + * EAI_NONAME will be set below if no better code is found. + */ + if (terror == 0 || terror == EAI_NONAME) { + if (terror4 != 0 && terror4 != EAI_NONAME) + terror = terror4; + else if (terror6 != 0 && terror6 != EAI_NONAME) + terror = terror6; + } + + isc_mem_put(mctx, resstate, sizeof(*resstate)); + } + + if (*aip == NULL) { + error = terror; + if (error == 0) + error = EAI_NONAME; + } + +#if 1 /* XXX: enabled for finding leaks. should be cleaned up later. */ + isc_app_ctxfinish(actx); + irs_context_destroy(&irsctx); +#endif + + return (error); +} + +static char * +irs_strsep(char **stringp, const char *delim) { + char *string = *stringp; + char *s; + const char *d; + char sc, dc; + + if (string == NULL) + return (NULL); + + for (s = string; *s != '\0'; s++) { + sc = *s; + for (d = delim; (dc = *d) != '\0'; d++) + if (sc == dc) { + *s++ = '\0'; + *stringp = s; + return (string); + } + } + *stringp = NULL; + return (string); +} + +static void +set_order(int family, int (**net_order)(const char *, int, struct addrinfo **, + int, int)) +{ + char *order, *tok; + int found; + + if (family) { + switch (family) { + case AF_INET: + *net_order++ = add_ipv4; + break; + case AF_INET6: + *net_order++ = add_ipv6; + break; + } + } else { + order = getenv("NET_ORDER"); + found = 0; + while (order != NULL) { + /* + * We ignore any unknown names. + */ + tok = irs_strsep(&order, ":"); + if (strcasecmp(tok, "inet6") == 0) { + if ((found & FOUND_IPV6) == 0) + *net_order++ = add_ipv6; + found |= FOUND_IPV6; + } else if (strcasecmp(tok, "inet") == 0 || + strcasecmp(tok, "inet4") == 0) { + if ((found & FOUND_IPV4) == 0) + *net_order++ = add_ipv4; + found |= FOUND_IPV4; + } + } + + /* + * Add in anything that we didn't find. + */ + if ((found & FOUND_IPV4) == 0) + *net_order++ = add_ipv4; + if ((found & FOUND_IPV6) == 0) + *net_order++ = add_ipv6; + } + *net_order = NULL; + return; +} + +static char v4_loop[4] = { 127, 0, 0, 1 }; + +static int +add_ipv4(const char *hostname, int flags, struct addrinfo **aip, + int socktype, int port) +{ + struct addrinfo *ai; + + UNUSED(hostname); + UNUSED(flags); + + ai = ai_clone(*aip, AF_INET); /* don't use ai_clone() */ + if (ai == NULL) { + freeaddrinfo(*aip); + return (EAI_MEMORY); + } + + *aip = ai; + ai->ai_socktype = socktype; + SIN(ai->ai_addr)->sin_port = port; + memcpy(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4); + + return (0); +} + +static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + +static int +add_ipv6(const char *hostname, int flags, struct addrinfo **aip, + int socktype, int port) +{ + struct addrinfo *ai; + + UNUSED(hostname); + UNUSED(flags); + + ai = ai_clone(*aip, AF_INET6); /* don't use ai_clone() */ + if (ai == NULL) { + freeaddrinfo(*aip); + return (EAI_MEMORY); + } + + *aip = ai; + ai->ai_socktype = socktype; + SIN6(ai->ai_addr)->sin6_port = port; + memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16); + + return (0); +} + +/*% Free address info. */ +void +freeaddrinfo(struct addrinfo *ai) { + struct addrinfo *ai_next; + + while (ai != NULL) { + ai_next = ai->ai_next; + if (ai->ai_addr != NULL) + free(ai->ai_addr); + if (ai->ai_canonname) + free(ai->ai_canonname); + free(ai); + ai = ai_next; + } +} + +#ifdef AF_LOCAL +static int +get_local(const char *name, int socktype, struct addrinfo **res) { + struct addrinfo *ai; + struct sockaddr_un *slocal; + + if (socktype == 0) + return (EAI_SOCKTYPE); + + ai = ai_alloc(AF_LOCAL, sizeof(*slocal)); + if (ai == NULL) + return (EAI_MEMORY); + + slocal = SLOCAL(ai->ai_addr); + strncpy(slocal->sun_path, name, sizeof(slocal->sun_path)); + + ai->ai_socktype = socktype; + /* + * ai->ai_flags, ai->ai_protocol, ai->ai_canonname, + * and ai->ai_next were initialized to zero. + */ + + *res = ai; + return (0); +} +#endif + +/*! + * Allocate an addrinfo structure, and a sockaddr structure + * of the specificed length. We initialize: + * ai_addrlen + * ai_family + * ai_addr + * ai_addr->sa_family + * ai_addr->sa_len (IRS_PLATFORM_HAVESALEN) + * and everything else is initialized to zero. + */ +static struct addrinfo * +ai_alloc(int family, int addrlen) { + struct addrinfo *ai; + + ai = (struct addrinfo *)calloc(1, sizeof(*ai)); + if (ai == NULL) + return (NULL); + + ai->ai_addr = SA(calloc(1, addrlen)); + if (ai->ai_addr == NULL) { + free(ai); + return (NULL); + } + ai->ai_addrlen = addrlen; + ai->ai_family = family; + ai->ai_addr->sa_family = family; +#ifdef IRS_PLATFORM_HAVESALEN + ai->ai_addr->sa_len = addrlen; +#endif + return (ai); +} + +static struct addrinfo * +ai_clone(struct addrinfo *oai, int family) { + struct addrinfo *ai; + + ai = ai_alloc(family, ((family == AF_INET6) ? + sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))); + + if (ai == NULL) { + if (oai != NULL) + freeaddrinfo(oai); + return (NULL); + } + if (oai == NULL) + return (ai); + + ai->ai_flags = oai->ai_flags; + ai->ai_socktype = oai->ai_socktype; + ai->ai_protocol = oai->ai_protocol; + ai->ai_canonname = NULL; + ai->ai_next = oai; + return (ai); +} + +static struct addrinfo * +ai_reverse(struct addrinfo *oai) { + struct addrinfo *nai, *tai; + + nai = NULL; + + while (oai != NULL) { + /* + * Grab one off the old list. + */ + tai = oai; + oai = oai->ai_next; + /* + * Put it on the front of the new list. + */ + tai->ai_next = nai; + nai = tai; + } + return (nai); +} + + +static struct addrinfo * +ai_concat(struct addrinfo *ai1, struct addrinfo *ai2) { + struct addrinfo *ai_tmp; + + if (ai1 == NULL) + return (ai2); + else if (ai2 == NULL) + return (ai1); + + for (ai_tmp = ai1; ai_tmp != NULL && ai_tmp->ai_next != NULL; + ai_tmp = ai_tmp->ai_next) + ; + + ai_tmp->ai_next = ai2; + + return (ai1); +} diff --git a/lib/irs/getnameinfo.c b/lib/irs/getnameinfo.c new file mode 100644 index 0000000..fadd8d8 --- /dev/null +++ b/lib/irs/getnameinfo.c @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: getnameinfo.c,v 1.4 2009-09-02 23:48:02 tbox Exp $ */ + +/*! \file */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * 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 project 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 PROJECT 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 PROJECT 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. + */ + +/** + * getnameinfo() returns the hostname for the struct sockaddr sa which is + * salen bytes long. The hostname is of length hostlen and is returned via + * *host. The maximum length of the hostname is 1025 bytes: #NI_MAXHOST. + * + * The name of the service associated with the port number in sa is + * returned in *serv. It is servlen bytes long. The maximum length of the + * service name is #NI_MAXSERV - 32 bytes. + * + * The flags argument sets the following bits: + * + * \li #NI_NOFQDN: + * A fully qualified domain name is not required for local hosts. + * The local part of the fully qualified domain name is returned + * instead. + * + * \li #NI_NUMERICHOST + * Return the address in numeric form, as if calling inet_ntop(), + * instead of a host name. + * + * \li #NI_NAMEREQD + * A name is required. If the hostname cannot be found in the DNS + * and this flag is set, a non-zero error code is returned. If the + * hostname is not found and the flag is not set, the address is + * returned in numeric form. + * + * \li #NI_NUMERICSERV + * The service name is returned as a digit string representing the + * port number. + * + * \li #NI_DGRAM + * Specifies that the service being looked up is a datagram + * service, and causes getservbyport() to be called with a second + * argument of "udp" instead of its default of "tcp". This is + * required for the few ports (512-514) that have different + * services for UDP and TCP. + * + * \section getnameinfo_return Return Values + * + * getnameinfo() returns 0 on success or a non-zero error code if + * an error occurs. + * + * \section getname_see See Also + * + * RFC3493, getservbyport(), + * getnamebyaddr(). inet_ntop(). + */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define SUCCESS 0 + +/*% afd structure definition */ +static struct afd { + int a_af; + size_t a_addrlen; + size_t a_socklen; +} afdl [] = { + /*! + * First entry is linked last... + */ + { AF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in) }, + { AF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6) }, + {0, 0, 0}, +}; + +/*! + * The test against 0 is there to keep the Solaris compiler + * from complaining about "end-of-loop code not reached". + */ +#define ERR(code) \ + do { result = (code); \ + if (result != 0) goto cleanup; \ + } while (0) + +int +getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, + IRS_GETNAMEINFO_BUFLEN_T hostlen, char *serv, + IRS_GETNAMEINFO_BUFLEN_T servlen, IRS_GETNAMEINFO_FLAGS_T flags) +{ + struct afd *afd; + struct servent *sp; + unsigned short port; +#ifdef IRS_PLATFORM_HAVESALEN + size_t len; +#endif + int family, i; + const void *addr; + char *p; +#if 0 + unsigned long v4a; + unsigned char pfx; +#endif + char numserv[sizeof("65000")]; + char numaddr[sizeof("abcd:abcd:abcd:abcd:abcd:abcd:255.255.255.255") + + 1 + sizeof("4294967295")]; + const char *proto; + int result = SUCCESS; + + if (sa == NULL) + ERR(EAI_FAIL); + +#ifdef IRS_PLATFORM_HAVESALEN + len = sa->sa_len; + if (len != salen) + ERR(EAI_FAIL); +#endif + + family = sa->sa_family; + for (i = 0; afdl[i].a_af; i++) + if (afdl[i].a_af == family) { + afd = &afdl[i]; + goto found; + } + ERR(EAI_FAMILY); + + found: + if (salen != afd->a_socklen) + ERR(EAI_FAIL); + + switch (family) { + case AF_INET: + port = ((const struct sockaddr_in *)sa)->sin_port; + addr = &((const struct sockaddr_in *)sa)->sin_addr.s_addr; + break; + + case AF_INET6: + port = ((const struct sockaddr_in6 *)sa)->sin6_port; + addr = ((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr; + break; + + default: + port = 0; + addr = NULL; + INSIST(0); + } + proto = (flags & NI_DGRAM) ? "udp" : "tcp"; + + if (serv == NULL || servlen == 0U) { + /* + * Caller does not want service. + */ + } else if ((flags & NI_NUMERICSERV) != 0 || + (sp = getservbyport(port, proto)) == NULL) { + snprintf(numserv, sizeof(numserv), "%d", ntohs(port)); + if ((strlen(numserv) + 1) > servlen) + ERR(EAI_OVERFLOW); + strcpy(serv, numserv); + } else { + if ((strlen(sp->s_name) + 1) > servlen) + ERR(EAI_OVERFLOW); + strcpy(serv, sp->s_name); + } + +#if 0 + switch (sa->sa_family) { + case AF_INET: + v4a = ((struct sockaddr_in *)sa)->sin_addr.s_addr; + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + flags |= NI_NUMERICHOST; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0 || v4a == IN_LOOPBACKNET) + flags |= NI_NUMERICHOST; + break; + + case AF_INET6: + pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0]; + if (pfx == 0 || pfx == 0xfe || pfx == 0xff) + flags |= NI_NUMERICHOST; + break; + } +#endif + + if (host == NULL || hostlen == 0U) { + /* + * do nothing in this case. + * in case you are wondering if "&&" is more correct than + * "||" here: RFC3493 says that host == NULL or hostlen == 0 + * means that the caller does not want the result. + */ + } else if ((flags & NI_NUMERICHOST) != 0) { + if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + ERR(EAI_SYSTEM); +#if defined(IRS_HAVE_SIN6_SCOPE_ID) + if (afd->a_af == AF_INET6 && + ((const struct sockaddr_in6 *)sa)->sin6_scope_id) { + char *p = numaddr + strlen(numaddr); + const char *stringscope = NULL; +#ifdef VENDOR_SPECIFIC + /* + * Vendors may want to add support for + * non-numeric scope identifier. + */ + stringscope = foo; +#endif + if (stringscope == NULL) { + snprintf(p, sizeof(numaddr) - (p - numaddr), + "%%%u", + ((const struct sockaddr_in6 *)sa)->sin6_scope_id); + } else { + snprintf(p, sizeof(numaddr) - (p - numaddr), + "%%%s", stringscope); + } + } +#endif + if (strlen(numaddr) + 1 > hostlen) + ERR(EAI_OVERFLOW); + strcpy(host, numaddr); + } else { + isc_netaddr_t netaddr; + dns_fixedname_t ptrfname; + dns_name_t *ptrname; + irs_context_t *irsctx = NULL; + dns_client_t *client; + isc_boolean_t found = ISC_FALSE; + dns_namelist_t answerlist; + dns_rdataset_t *rdataset; + isc_region_t hostregion; + char hoststr[1024]; /* is this enough? */ + isc_result_t iresult; + + /* Get IRS context and the associated DNS client object */ + iresult = irs_context_get(&irsctx); + if (iresult != ISC_R_SUCCESS) + ERR(EAI_FAIL); + client = irs_context_getdnsclient(irsctx); + + /* Make query name */ + isc_netaddr_fromsockaddr(&netaddr, (const isc_sockaddr_t *)sa); + dns_fixedname_init(&ptrfname); + ptrname = dns_fixedname_name(&ptrfname); + iresult = dns_byaddr_createptrname2(&netaddr, 0, ptrname); + if (iresult != ISC_R_SUCCESS) + ERR(EAI_FAIL); + + /* Get the PTR RRset */ + ISC_LIST_INIT(answerlist); + iresult = dns_client_resolve(client, ptrname, + dns_rdataclass_in, + dns_rdatatype_ptr, + DNS_CLIENTRESOPT_ALLOWRUN, + &answerlist); + switch (iresult) { + case ISC_R_SUCCESS: + /* + * a 'non-existent' error is not necessarily fatal for + * getnameinfo(). + */ + case DNS_R_NCACHENXDOMAIN: + case DNS_R_NCACHENXRRSET: + break; + case DNS_R_SIGINVALID: + case DNS_R_SIGEXPIRED: + case DNS_R_SIGFUTURE: + case DNS_R_KEYUNAUTHORIZED: + case DNS_R_MUSTBESECURE: + case DNS_R_COVERINGNSEC: + case DNS_R_NOTAUTHORITATIVE: + case DNS_R_NOVALIDKEY: + case DNS_R_NOVALIDDS: + case DNS_R_NOVALIDSIG: + ERR(EAI_INSECUREDATA); + default: + ERR(EAI_FAIL); + } + + /* Parse the answer for the hostname */ + for (ptrname = ISC_LIST_HEAD(answerlist); ptrname != NULL; + ptrname = ISC_LIST_NEXT(ptrname, link)) { + for (rdataset = ISC_LIST_HEAD(ptrname->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) { + if (!dns_rdataset_isassociated(rdataset)) + continue; + if (rdataset->type != dns_rdatatype_ptr) + continue; + + for (iresult = dns_rdataset_first(rdataset); + iresult == ISC_R_SUCCESS; + iresult = dns_rdataset_next(rdataset)) { + dns_rdata_t rdata; + dns_rdata_ptr_t rdata_ptr; + isc_buffer_t b; + + dns_rdata_init(&rdata); + dns_rdataset_current(rdataset, &rdata); + dns_rdata_tostruct(&rdata, &rdata_ptr, + NULL); + + isc_buffer_init(&b, hoststr, + sizeof(hoststr)); + iresult = + dns_name_totext(&rdata_ptr.ptr, + ISC_TRUE, &b); + dns_rdata_freestruct(&rdata_ptr); + if (iresult == ISC_R_SUCCESS) { + /* + * We ignore the rest of the + * answer. After all, + * getnameinfo() can return + * at most one hostname. + */ + found = ISC_TRUE; + isc_buffer_usedregion( + &b, &hostregion); + goto ptrfound; + } + + } + } + } + ptrfound: + dns_client_freeresanswer(client, &answerlist); + if (found) { + if ((flags & NI_NOFQDN) != 0) { + p = strchr(hoststr, '.'); + if (p) + *p = '\0'; + } + if (hostregion.length + 1 > hostlen) + ERR(EAI_OVERFLOW); + snprintf(host, hostlen, "%.*s", + (int)hostregion.length, + (char *)hostregion.base); + } else { + if ((flags & NI_NAMEREQD) != 0) + ERR(EAI_NONAME); + if (inet_ntop(afd->a_af, addr, numaddr, + sizeof(numaddr)) == NULL) + ERR(EAI_SYSTEM); + if ((strlen(numaddr) + 1) > hostlen) + ERR(EAI_OVERFLOW); + strcpy(host, numaddr); + } + } + result = SUCCESS; + + cleanup: + return (result); +} diff --git a/lib/irs/include/Makefile.in b/lib/irs/include/Makefile.in new file mode 100644 index 0000000..22a63ee --- /dev/null +++ b/lib/irs/include/Makefile.in @@ -0,0 +1,24 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +SUBDIRS = irs +TARGETS = + +@BIND9_MAKE_RULES@ diff --git a/lib/irs/include/irs/Makefile.in b/lib/irs/include/irs/Makefile.in new file mode 100644 index 0000000..7d50995 --- /dev/null +++ b/lib/irs/include/irs/Makefile.in @@ -0,0 +1,44 @@ +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC 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. + +# $Id: Makefile.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +# +# Only list headers that are to be installed and are not +# machine generated. The latter are handled specially in the +# install target below. +# +HEADERS = version.h + +SUBDIRS = +TARGETS = + +@BIND9_MAKE_RULES@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/irs + +install:: installdirs + for i in ${HEADERS}; do \ + ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/irs ; \ + done + ${INSTALL_DATA} netdb.h ${DESTDIR}${includedir}/irs + ${INSTALL_DATA} platform.h ${DESTDIR}${includedir}/irs + +distclean:: + rm -f netdb.h platform.h diff --git a/lib/irs/include/irs/context.h b/lib/irs/include/irs/context.h new file mode 100644 index 0000000..c49cfcf --- /dev/null +++ b/lib/irs/include/irs/context.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: context.h,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +#ifndef IRS_CONTEXT_H +#define IRS_CONTEXT_H 1 + +/*! \file + * + * \brief + * The IRS context module provides an abstract interface to the DNS library + * with an application. An IRS context object initializes and holds various + * resources used in the DNS library. + */ + +#include +#include + +ISC_LANG_BEGINDECLS + +isc_result_t +irs_context_create(irs_context_t **contextp); +/*%< + * Create an IRS context. It internally initializes the ISC and DNS libraries + * (if not yet), creates a DNS client object and initializes the client using + * the configuration files parsed via the 'resconf' and 'dnsconf' IRS modules. + * Some of the internally initialized objects can be used by the application + * via irs_context_getxxx() functions (see below). + * + * Requires: + * + *\li contextp != NULL && *contextp == NULL. + */ + +isc_result_t +irs_context_get(irs_context_t **contextp); +/*%< + * Return an IRS context for the calling thread. If no IRS context is + * associated to the thread, this function creates a new one by calling + * irs_context_create(), and associates it with the thread as a thread specific + * data value. This function is provided for standard libraries that are + * expected to be thread-safe but do not accept an appropriate IRS context + * as a library parameter, e.g., getaddrinfo(). + * + * Requires: + * + *\li contextp != NULL && *contextp == NULL. + */ + +void +irs_context_destroy(irs_context_t **contextp); +/*%< + * Destroy an IRS context. + * + * Requires: + * + *\li '*contextp' is a valid IRS context. + * + * Ensures: + *\li '*contextp' == NULL. + */ + +isc_mem_t * +irs_context_getmctx(irs_context_t *context); +/*%< + * Return the memory context held in the context. + * + * Requires: + * + *\li 'context' is a valid IRS context. + */ + +isc_appctx_t * +irs_context_getappctx(irs_context_t *context); +/*%< + * Return the application context held in the context. + * + * Requires: + * + *\li 'context' is a valid IRS context. + */ + +isc_taskmgr_t * +irs_context_gettaskmgr(irs_context_t *context); +/*%< + * Return the task manager held in the context. + * + * Requires: + * + *\li 'context' is a valid IRS context. + */ + +isc_timermgr_t * +irs_context_gettimermgr(irs_context_t *context); +/*%< + * Return the timer manager held in the context. + * + * Requires: + * + *\li 'context' is a valid IRS context. + */ + +isc_task_t * +irs_context_gettask(irs_context_t *context); +/*%< + * Return the task object held in the context. + * + * Requires: + * + *\li 'context' is a valid IRS context. + */ + +dns_client_t * +irs_context_getdnsclient(irs_context_t *context); +/*%< + * Return the DNS client object held in the context. + * + * Requires: + * + *\li 'context' is a valid IRS context. + */ + +irs_resconf_t * +irs_context_getresconf(irs_context_t *context); +/*%< + * Return the resolver configuration object held in the context. + * + * Requires: + * + *\li 'context' is a valid IRS context. + */ + +irs_dnsconf_t * +irs_context_getdnsconf(irs_context_t *context); +/*%< + * Return the advanced DNS configuration object held in the context. + * + * Requires: + * + *\li 'context' is a valid IRS context. + */ + +ISC_LANG_ENDDECLS + +#endif /* IRS_CONTEXT_H */ diff --git a/lib/irs/include/irs/dnsconf.h b/lib/irs/include/irs/dnsconf.h new file mode 100644 index 0000000..0041c16 --- /dev/null +++ b/lib/irs/include/irs/dnsconf.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: dnsconf.h,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +#ifndef IRS_DNSCONF_H +#define IRS_DNSCONF_H 1 + +/*! \file + * + * \brief + * The IRS dnsconf module parses an "advanced" configuration file related to + * the DNS library, such as trusted keys for DNSSEC validation, and creates + * the corresponding configuration objects for the DNS library modules. + * + * Notes: + * This module is very experimental and the configuration syntax or library + * interfaces may change in future versions. Currently, only the + * 'trusted-keys' statement is supported, whose syntax is the same as the + * same name of statement for named.conf. + */ + +#include + +/*% + * A compound structure storing DNS key information mainly for DNSSEC + * validation. A dns_key_t object will be created using the 'keyname' and + * 'keydatabuf' members with the dst_key_fromdns() function. + */ +typedef struct irs_dnsconf_dnskey { + dns_name_t *keyname; + isc_buffer_t *keydatabuf; + ISC_LINK(struct irs_dnsconf_dnskey) link; +} irs_dnsconf_dnskey_t; + +typedef ISC_LIST(irs_dnsconf_dnskey_t) irs_dnsconf_dnskeylist_t; + +ISC_LANG_BEGINDECLS + +isc_result_t +irs_dnsconf_load(isc_mem_t *mctx, const char *filename, irs_dnsconf_t **confp); +/*%< + * Load the "advanced" DNS configuration file 'filename' in the "dns.conf" + * format, and create a new irs_dnsconf_t object from the configuration. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'filename' != NULL + * + *\li 'confp' != NULL && '*confp' == NULL + */ + +void +irs_dnsconf_destroy(irs_dnsconf_t **confp); +/*%< + * Destroy the dnsconf object. + * + * Requires: + * + *\li '*confp' is a valid dnsconf object. + * + * Ensures: + * + *\li *confp == NULL + */ + +irs_dnsconf_dnskeylist_t * +irs_dnsconf_gettrustedkeys(irs_dnsconf_t *conf); +/*%< + * Return a list of key information stored in 'conf'. + * + * Requires: + * + *\li 'conf' is a valid dnsconf object. + */ + +ISC_LANG_ENDDECLS + +#endif /* IRS_DNSCONF_H */ diff --git a/lib/irs/include/irs/netdb.h.in b/lib/irs/include/irs/netdb.h.in new file mode 100644 index 0000000..9dda413 --- /dev/null +++ b/lib/irs/include/irs/netdb.h.in @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: netdb.h.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +/*! \file */ + +#ifndef IRS_NETDB_H +#define IRS_NETDB_H 1 + +#include /* Required on FreeBSD (and others?) for size_t. */ +#include /* Contractual provision. */ + +/* + * Define if does not declare struct addrinfo. + */ +@ISC_IRS_NEEDADDRINFO@ + +#ifdef ISC_IRS_NEEDADDRINFO +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* Length of ai_addr */ + char *ai_canonname; /* Canonical name for hostname */ + struct sockaddr *ai_addr; /* Binary address */ + struct addrinfo *ai_next; /* Next structure in linked list */ +}; +#endif + +/* + * Undefine all #defines we are interested in as may or may not have + * defined them. + */ + +/* + * Error return codes from gethostbyname() and gethostbyaddr() + * (left in extern int h_errno). + */ + +#undef NETDB_INTERNAL +#undef NETDB_SUCCESS +#undef HOST_NOT_FOUND +#undef TRY_AGAIN +#undef NO_RECOVERY +#undef NO_DATA +#undef NO_ADDRESS + +#define NETDB_INTERNAL -1 /* see errno */ +#define NETDB_SUCCESS 0 /* no problem */ +#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ +#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */ +#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ +#define NO_DATA 4 /* Valid name, no data record of requested type */ +#define NO_ADDRESS NO_DATA /* no address, look for MX record */ + +/* + * Error return codes from getaddrinfo(). EAI_INSECUREDATA is our own extension + * and it's very unlikely to be already defined, but undef it just in case; it + * at least doesn't do any harm. + */ + +#undef EAI_ADDRFAMILY +#undef EAI_AGAIN +#undef EAI_BADFLAGS +#undef EAI_FAIL +#undef EAI_FAMILY +#undef EAI_MEMORY +#undef EAI_NODATA +#undef EAI_NONAME +#undef EAI_SERVICE +#undef EAI_SOCKTYPE +#undef EAI_SYSTEM +#undef EAI_BADHINTS +#undef EAI_PROTOCOL +#undef EAI_OVERFLOW +#undef EAI_INSECUREDATA +#undef EAI_MAX + +#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */ +#define EAI_AGAIN 2 /* temporary failure in name resolution */ +#define EAI_BADFLAGS 3 /* invalid value for ai_flags */ +#define EAI_FAIL 4 /* non-recoverable failure in name resolution */ +#define EAI_FAMILY 5 /* ai_family not supported */ +#define EAI_MEMORY 6 /* memory allocation failure */ +#define EAI_NODATA 7 /* no address associated with hostname */ +#define EAI_NONAME 8 /* hostname nor servname provided, or not known */ +#define EAI_SERVICE 9 /* servname not supported for ai_socktype */ +#define EAI_SOCKTYPE 10 /* ai_socktype not supported */ +#define EAI_SYSTEM 11 /* system error returned in errno */ +#define EAI_BADHINTS 12 +#define EAI_PROTOCOL 13 +#define EAI_OVERFLOW 14 +#define EAI_INSECUREDATA 15 +#define EAI_MAX 16 + +/* + * Flag values for getaddrinfo() + */ +#undef AI_PASSIVE +#undef AI_CANONNAME +#undef AI_NUMERICHOST + +#define AI_PASSIVE 0x00000001 +#define AI_CANONNAME 0x00000002 +#define AI_NUMERICHOST 0x00000004 + +/* + * Flag values for getipnodebyname() + */ +#undef AI_V4MAPPED +#undef AI_ALL +#undef AI_ADDRCONFIG +#undef AI_DEFAULT + +#define AI_V4MAPPED 0x00000008 +#define AI_ALL 0x00000010 +#define AI_ADDRCONFIG 0x00000020 +#define AI_DEFAULT (AI_V4MAPPED|AI_ADDRCONFIG) + +/* + * Constants for lwres_getnameinfo() + */ +#undef NI_MAXHOST +#undef NI_MAXSERV + +#define NI_MAXHOST 1025 +#define NI_MAXSERV 32 + +/* + * Flag values for lwres_getnameinfo() + */ +#undef NI_NOFQDN +#undef NI_NUMERICHOST +#undef NI_NAMEREQD +#undef NI_NUMERICSERV +#undef NI_DGRAM +#undef NI_NUMERICSCOPE + +#define NI_NOFQDN 0x00000001 +#define NI_NUMERICHOST 0x00000002 +#define NI_NAMEREQD 0x00000004 +#define NI_NUMERICSERV 0x00000008 +#define NI_DGRAM 0x00000010 + +/* + * Tell Emacs to use C mode on this file. + * Local variables: + * mode: c + * End: + */ + +#endif /* IRS_NETDB_H */ diff --git a/lib/irs/include/irs/platform.h.in b/lib/irs/include/irs/platform.h.in new file mode 100644 index 0000000..f61f671 --- /dev/null +++ b/lib/irs/include/irs/platform.h.in @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: platform.h.in,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +/*! \file */ + +#ifndef IRS_PLATFORM_H +#define IRS_PLATFORM_H 1 + +/***** + ***** Platform-dependent defines. + *****/ + +#ifndef IRS_PLATFORM_USEDECLSPEC +#define LIBIRS_EXTERNAL_DATA +#else +#ifdef LIBIRS_EXPORTS +#define LIBIRS_EXTERNAL_DATA __declspec(dllexport) +#else +#define LIBIRS_EXTERNAL_DATA __declspec(dllimport) +#endif +#endif + +/* + * Tell Emacs to use C mode on this file. + * Local Variables: + * mode: c + * End: + */ + +#endif /* IRS_PLATFORM_H */ diff --git a/lib/irs/include/irs/resconf.h b/lib/irs/include/irs/resconf.h new file mode 100644 index 0000000..8249c7b --- /dev/null +++ b/lib/irs/include/irs/resconf.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: resconf.h,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +#ifndef IRS_RESCONF_H +#define IRS_RESCONF_H 1 + +/*! \file + * + * \brief + * The IRS resconf module parses the legacy "/etc/resolv.conf" file and + * creates the corresponding configuration objects for the DNS library + * modules. + */ + +#include + +/*% + * A DNS search list specified in the 'domain' or 'search' statements + * in the "resolv.conf" file. + */ +typedef struct irs_resconf_search { + char *domain; + ISC_LINK(struct irs_resconf_search) link; +} irs_resconf_search_t; + +typedef ISC_LIST(irs_resconf_search_t) irs_resconf_searchlist_t; + +ISC_LANG_BEGINDECLS + +isc_result_t +irs_resconf_load(isc_mem_t *mctx, const char *filename, irs_resconf_t **confp); +/*%< + * Load the resolver configuration file 'filename' in the "resolv.conf" format, + * and create a new irs_resconf_t object from the configuration. + * + * Notes: + * + *\li Currently, only the following options are supported: + * nameserver, domain, search, sortlist, ndots, and options. + * In addition, 'sortlist' is not actually effective; it's parsed, but + * the application cannot use the configuration. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'filename' != NULL + * + *\li 'confp' != NULL && '*confp' == NULL + */ + +void +irs_resconf_destroy(irs_resconf_t **confp); +/*%< + * Destroy the resconf object. + * + * Requires: + * + *\li '*confp' is a valid resconf object. + * + * Ensures: + * + *\li *confp == NULL + */ + +isc_sockaddrlist_t * +irs_resconf_getnameservers(irs_resconf_t *conf); +/*%< + * Return a list of name server addresses stored in 'conf'. + * + * Requires: + * + *\li 'conf' is a valid resconf object. + */ + +irs_resconf_searchlist_t * +irs_resconf_getsearchlist(irs_resconf_t *conf); +/*%< + * Return the search list stored in 'conf'. + * + * Requires: + * + *\li 'conf' is a valid resconf object. + */ + +unsigned int +irs_resconf_getndots(irs_resconf_t *conf); +/*%< + * Return the 'ndots' value stored in 'conf'. + * + * Requires: + * + *\li 'conf' is a valid resconf object. + */ + +ISC_LANG_ENDDECLS + +#endif /* IRS_RESCONF_H */ diff --git a/lib/irs/include/irs/types.h b/lib/irs/include/irs/types.h new file mode 100644 index 0000000..4b8a804 --- /dev/null +++ b/lib/irs/include/irs/types.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: types.h,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +#ifndef IRS_TYPES_H +#define IRS_TYPES_H 1 + +/* Core Types. Alphabetized by defined type. */ + +/*%< per-thread IRS context */ +typedef struct irs_context irs_context_t; +/*%< resolv.conf configuration information */ +typedef struct irs_resconf irs_resconf_t; +/*%< advanced DNS-related configuration information */ +typedef struct irs_dnsconf irs_dnsconf_t; + +#endif /* IRS_TYPES_H */ diff --git a/lib/irs/include/irs/version.h b/lib/irs/include/irs/version.h new file mode 100644 index 0000000..f43aa14 --- /dev/null +++ b/lib/irs/include/irs/version.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: version.h,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +/*! \file */ + +#include + +LIBIRS_EXTERNAL_DATA extern const char irs_version[]; + +LIBIRS_EXTERNAL_DATA extern const unsigned int irs_libinterface; +LIBIRS_EXTERNAL_DATA extern const unsigned int irs_librevision; +LIBIRS_EXTERNAL_DATA extern const unsigned int irs_libage; diff --git a/lib/irs/resconf.c b/lib/irs/resconf.c new file mode 100644 index 0000000..af1413b --- /dev/null +++ b/lib/irs/resconf.c @@ -0,0 +1,636 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: resconf.c,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +/*! \file resconf.c */ + +/** + * Module for parsing resolv.conf files (largely derived from lwconfig.c). + * + * irs_resconf_load() opens the file filename and parses it to initialize + * the configuration structure. + * + * \section lwconfig_return Return Values + * + * irs_resconf_load() returns #IRS_R_SUCCESS if it successfully read and + * parsed filename. It returns a non-0 error code if filename could not be + * opened or contained incorrect resolver statements. + * + * \section lwconfig_see See Also + * + * stdio(3), \link resolver resolver \endlink + * + * \section files Files + * + * /etc/resolv.conf + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define IRS_RESCONF_MAGIC ISC_MAGIC('R', 'E', 'S', 'c') +#define IRS_RESCONF_VALID(c) ISC_MAGIC_VALID(c, IRS_RESCONF_MAGIC) + +/*! + * protocol constants + */ + +#if ! defined(NS_INADDRSZ) +#define NS_INADDRSZ 4 +#endif + +#if ! defined(NS_IN6ADDRSZ) +#define NS_IN6ADDRSZ 16 +#endif + +/*! + * resolv.conf parameters + */ + +#define RESCONFMAXNAMESERVERS 3 /*%< max 3 "nameserver" entries */ +#define RESCONFMAXSEARCH 8 /*%< max 8 domains in "search" entry */ +#define RESCONFMAXLINELEN 256 /*%< max size of a line */ +#define RESCONFMAXSORTLIST 10 /*%< max 10 */ + +/*! + * configuration data structure + */ + +struct irs_resconf { + /* + * The configuration data is a thread-specific object, and does not + * need to be locked. + */ + unsigned int magic; + isc_mem_t *mctx; + + isc_sockaddrlist_t nameservers; + unsigned int numns; /*%< number of configured servers */ + + char *domainname; + char *search[RESCONFMAXSEARCH]; + isc_uint8_t searchnxt; /*%< index for next free slot */ + + irs_resconf_searchlist_t searchlist; + + struct { + isc_netaddr_t addr; + /*% mask has a non-zero 'family' if set */ + isc_netaddr_t mask; + } sortlist[RESCONFMAXSORTLIST]; + isc_uint8_t sortlistnxt; + + /*%< non-zero if 'options debug' set */ + isc_uint8_t resdebug; + /*%< set to n in 'options ndots:n' */ + isc_uint8_t ndots; +}; + +static isc_result_t +resconf_parsenameserver(irs_resconf_t *conf, FILE *fp); +static isc_result_t +resconf_parsedomain(irs_resconf_t *conf, FILE *fp); +static isc_result_t +resconf_parsesearch(irs_resconf_t *conf, FILE *fp); +static isc_result_t +resconf_parsesortlist(irs_resconf_t *conf, FILE *fp); +static isc_result_t +resconf_parseoption(irs_resconf_t *ctx, FILE *fp); + +/*! + * Eat characters from FP until EOL or EOF. Returns EOF or '\n' + */ +static int +eatline(FILE *fp) { + int ch; + + ch = fgetc(fp); + while (ch != '\n' && ch != EOF) + ch = fgetc(fp); + + return (ch); +} + +/*! + * Eats white space up to next newline or non-whitespace character (of + * EOF). Returns the last character read. Comments are considered white + * space. + */ +static int +eatwhite(FILE *fp) { + int ch; + + ch = fgetc(fp); + while (ch != '\n' && ch != EOF && isspace((unsigned char)ch)) + ch = fgetc(fp); + + if (ch == ';' || ch == '#') + ch = eatline(fp); + + return (ch); +} + +/*! + * Skip over any leading whitespace and then read in the next sequence of + * non-whitespace characters. In this context newline is not considered + * whitespace. Returns EOF on end-of-file, or the character + * that caused the reading to stop. + */ +static int +getword(FILE *fp, char *buffer, size_t size) { + int ch; + char *p = buffer; + + REQUIRE(buffer != NULL); + REQUIRE(size > 0U); + + *p = '\0'; + + ch = eatwhite(fp); + + if (ch == EOF) + return (EOF); + + do { + *p = '\0'; + + if (ch == EOF || isspace((unsigned char)ch)) + break; + else if ((size_t) (p - buffer) == size - 1) + return (EOF); /* Not enough space. */ + + *p++ = (char)ch; + ch = fgetc(fp); + } while (1); + + return (ch); +} + +static isc_result_t +add_server(isc_mem_t *mctx, const char *address_str, + isc_sockaddrlist_t *nameservers) +{ + int error; + isc_sockaddr_t *address = NULL; + struct addrinfo hints, *res; + isc_result_t result = ISC_R_SUCCESS; + + res = NULL; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(address_str, "53", &hints, &res); + if (error != 0) + return (ISC_R_BADADDRESSFORM); + + /* XXX: special case: treat all-0 IPv4 address as loopback */ + if (res->ai_family == AF_INET) { + struct in_addr *v4; + unsigned char zeroaddress[] = {0, 0, 0, 0}; + unsigned char loopaddress[] = {127, 0, 0, 1}; + + v4 = &((struct sockaddr_in *)res->ai_addr)->sin_addr; + if (memcmp(v4, zeroaddress, 4) == 0) + memcpy(v4, loopaddress, 4); + } + + address = isc_mem_get(mctx, sizeof(*address)); + if (address == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } + if (res->ai_addrlen > sizeof(address->type)) { + isc_mem_put(mctx, address, sizeof(*address)); + result = ISC_R_RANGE; + goto cleanup; + } + address->length = res->ai_addrlen; + memcpy(&address->type.sa, res->ai_addr, res->ai_addrlen); + ISC_LINK_INIT(address, link); + ISC_LIST_APPEND(*nameservers, address, link); + + cleanup: + freeaddrinfo(res); + + return (result); +} + +static isc_result_t +create_addr(const char *buffer, isc_netaddr_t *addr, int convert_zero) { + struct in_addr v4; + struct in6_addr v6; + + if (inet_aton(buffer, &v4) == 1) { + if (convert_zero) { + unsigned char zeroaddress[] = {0, 0, 0, 0}; + unsigned char loopaddress[] = {127, 0, 0, 1}; + if (memcmp(&v4, zeroaddress, 4) == 0) + memcpy(&v4, loopaddress, 4); + } + addr->family = AF_INET; + memcpy(&addr->type.in, &v4, NS_INADDRSZ); + addr->zone = 0; + } else if (inet_pton(AF_INET6, buffer, &v6) == 1) { + addr->family = AF_INET6; + memcpy(&addr->type.in6, &v6, NS_IN6ADDRSZ); + addr->zone = 0; + } else + return (ISC_R_BADADDRESSFORM); /* Unrecognised format. */ + + return (ISC_R_SUCCESS); +} + +static isc_result_t +resconf_parsenameserver(irs_resconf_t *conf, FILE *fp) { + char word[RESCONFMAXLINELEN]; + int cp; + isc_result_t result; + + if (conf->numns == RESCONFMAXNAMESERVERS) + return (ISC_R_SUCCESS); + + cp = getword(fp, word, sizeof(word)); + if (strlen(word) == 0U) + return (ISC_R_UNEXPECTEDEND); /* Nothing on line. */ + else if (cp == ' ' || cp == '\t') + cp = eatwhite(fp); + + if (cp != EOF && cp != '\n') + return (ISC_R_UNEXPECTEDTOKEN); /* Extra junk on line. */ + + result = add_server(conf->mctx, word, &conf->nameservers); + if (result != ISC_R_SUCCESS) + return (result); + conf->numns++; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +resconf_parsedomain(irs_resconf_t *conf, FILE *fp) { + char word[RESCONFMAXLINELEN]; + int res, i; + + res = getword(fp, word, sizeof(word)); + if (strlen(word) == 0U) + return (ISC_R_UNEXPECTEDEND); /* Nothing else on line. */ + else if (res == ' ' || res == '\t') + res = eatwhite(fp); + + if (res != EOF && res != '\n') + return (ISC_R_UNEXPECTEDTOKEN); /* Extra junk on line. */ + + if (conf->domainname != NULL) + isc_mem_free(conf->mctx, conf->domainname); + + /* + * Search and domain are mutually exclusive. + */ + for (i = 0; i < RESCONFMAXSEARCH; i++) { + if (conf->search[i] != NULL) { + isc_mem_free(conf->mctx, conf->search[i]); + conf->search[i] = NULL; + } + } + conf->searchnxt = 0; + + conf->domainname = isc_mem_strdup(conf->mctx, word); + if (conf->domainname == NULL) + return (ISC_R_NOMEMORY); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +resconf_parsesearch(irs_resconf_t *conf, FILE *fp) { + int idx, delim; + char word[RESCONFMAXLINELEN]; + + if (conf->domainname != NULL) { + /* + * Search and domain are mutually exclusive. + */ + isc_mem_free(conf->mctx, conf->domainname); + conf->domainname = NULL; + } + + /* + * Remove any previous search definitions. + */ + for (idx = 0; idx < RESCONFMAXSEARCH; idx++) { + if (conf->search[idx] != NULL) { + isc_mem_free(conf->mctx, conf->search[idx]); + conf->search[idx] = NULL; + } + } + conf->searchnxt = 0; + + delim = getword(fp, word, sizeof(word)); + if (strlen(word) == 0U) + return (ISC_R_UNEXPECTEDEND); /* Nothing else on line. */ + + idx = 0; + while (strlen(word) > 0U) { + if (conf->searchnxt == RESCONFMAXSEARCH) + goto ignore; /* Too many domains. */ + + conf->search[idx] = isc_mem_strdup(conf->mctx, word); + if (conf->search[idx] == NULL) + return (ISC_R_NOMEMORY); + idx++; + conf->searchnxt++; + + ignore: + if (delim == EOF || delim == '\n') + break; + else + delim = getword(fp, word, sizeof(word)); + } + + return (ISC_R_SUCCESS); +} + +static isc_result_t +resconf_parsesortlist(irs_resconf_t *conf, FILE *fp) { + int delim, res, idx; + char word[RESCONFMAXLINELEN]; + char *p; + + delim = getword(fp, word, sizeof(word)); + if (strlen(word) == 0U) + return (ISC_R_UNEXPECTEDEND); /* Empty line after keyword. */ + + while (strlen(word) > 0U) { + if (conf->sortlistnxt == RESCONFMAXSORTLIST) + return (ISC_R_QUOTA); /* Too many values. */ + + p = strchr(word, '/'); + if (p != NULL) + *p++ = '\0'; + + idx = conf->sortlistnxt; + res = create_addr(word, &conf->sortlist[idx].addr, 1); + if (res != ISC_R_SUCCESS) + return (res); + + if (p != NULL) { + res = create_addr(p, &conf->sortlist[idx].mask, 0); + if (res != ISC_R_SUCCESS) + return (res); + } else { + /* + * Make up a mask. (XXX: is this correct?) + */ + conf->sortlist[idx].mask = conf->sortlist[idx].addr; + memset(&conf->sortlist[idx].mask.type, 0xff, + sizeof(conf->sortlist[idx].mask.type)); + } + + conf->sortlistnxt++; + + if (delim == EOF || delim == '\n') + break; + else + delim = getword(fp, word, sizeof(word)); + } + + return (ISC_R_SUCCESS); +} + +static isc_result_t +resconf_parseoption(irs_resconf_t *conf, FILE *fp) { + int delim; + long ndots; + char *p; + char word[RESCONFMAXLINELEN]; + + delim = getword(fp, word, sizeof(word)); + if (strlen(word) == 0U) + return (ISC_R_UNEXPECTEDEND); /* Empty line after keyword. */ + + while (strlen(word) > 0U) { + if (strcmp("debug", word) == 0) { + conf->resdebug = 1; + } else if (strncmp("ndots:", word, 6) == 0) { + ndots = strtol(word + 6, &p, 10); + if (*p != '\0') /* Bad string. */ + return (ISC_R_UNEXPECTEDTOKEN); + if (ndots < 0 || ndots > 0xff) /* Out of range. */ + return (ISC_R_RANGE); + conf->ndots = (isc_uint8_t)ndots; + } + + if (delim == EOF || delim == '\n') + break; + else + delim = getword(fp, word, sizeof(word)); + } + + return (ISC_R_SUCCESS); +} + +static isc_result_t +add_search(irs_resconf_t *conf, char *domain) { + irs_resconf_search_t *entry; + + entry = isc_mem_get(conf->mctx, sizeof(*entry)); + if (entry == NULL) + return (ISC_R_NOMEMORY); + + entry->domain = domain; + ISC_LINK_INIT(entry, link); + ISC_LIST_APPEND(conf->searchlist, entry, link); + + return (ISC_R_SUCCESS); +} + +/*% parses a file and fills in the data structure. */ +isc_result_t +irs_resconf_load(isc_mem_t *mctx, const char *filename, irs_resconf_t **confp) +{ + FILE *fp = NULL; + char word[256]; + isc_result_t rval, ret; + irs_resconf_t *conf; + int i, stopchar; + + REQUIRE(mctx != NULL); + REQUIRE(filename != NULL); + REQUIRE(strlen(filename) > 0U); + REQUIRE(confp != NULL && *confp == NULL); + + conf = isc_mem_get(mctx, sizeof(*conf)); + if (conf == NULL) + return (ISC_R_NOMEMORY); + + conf->mctx = mctx; + ISC_LIST_INIT(conf->nameservers); + conf->numns = 0; + conf->domainname = NULL; + conf->searchnxt = 0; + conf->resdebug = 0; + conf->ndots = 1; + for (i = 0; i < RESCONFMAXSEARCH; i++) + conf->search[i] = NULL; + + errno = 0; + if ((fp = fopen(filename, "r")) == NULL) { + isc_mem_put(mctx, conf, sizeof(*conf)); + return (ISC_R_INVALIDFILE); + } + + ret = ISC_R_SUCCESS; + do { + stopchar = getword(fp, word, sizeof(word)); + if (stopchar == EOF) { + rval = ISC_R_SUCCESS; + break; + } + + if (strlen(word) == 0U) + rval = ISC_R_SUCCESS; + else if (strcmp(word, "nameserver") == 0) + rval = resconf_parsenameserver(conf, fp); + else if (strcmp(word, "domain") == 0) + rval = resconf_parsedomain(conf, fp); + else if (strcmp(word, "search") == 0) + rval = resconf_parsesearch(conf, fp); + else if (strcmp(word, "sortlist") == 0) + rval = resconf_parsesortlist(conf, fp); + else if (strcmp(word, "options") == 0) + rval = resconf_parseoption(conf, fp); + else { + /* unrecognised word. Ignore entire line */ + rval = ISC_R_SUCCESS; + stopchar = eatline(fp); + if (stopchar == EOF) { + break; + } + } + if (ret == ISC_R_SUCCESS && rval != ISC_R_SUCCESS) + ret = rval; + } while (1); + + fclose(fp); + + /* If we don't find a nameserver fall back to localhost */ + if (conf->numns == 0) { + INSIST(ISC_LIST_EMPTY(conf->nameservers)); + + /* XXX: should we catch errors? */ + (void)add_server(conf->mctx, "127.0.0.1", &conf->nameservers); + (void)add_server(conf->mctx, "::1", &conf->nameservers); + } + + /* + * Construct unified search list from domain or configured + * search list + */ + ISC_LIST_INIT(conf->searchlist); + if (conf->domainname != NULL) { + ret = add_search(conf, conf->domainname); + } else if (conf->searchnxt > 0) { + for (i = 0; i < conf->searchnxt; i++) { + ret = add_search(conf, conf->search[i]); + if (ret != ISC_R_SUCCESS) + break; + } + } + + conf->magic = IRS_RESCONF_MAGIC; + + if (ret != ISC_R_SUCCESS) + irs_resconf_destroy(&conf); + else + *confp = conf; + + return (ret); +} + +void +irs_resconf_destroy(irs_resconf_t **confp) { + irs_resconf_t *conf; + isc_sockaddr_t *address; + irs_resconf_search_t *searchentry; + int i; + + REQUIRE(confp != NULL); + conf = *confp; + REQUIRE(IRS_RESCONF_VALID(conf)); + + while ((searchentry = ISC_LIST_HEAD(conf->searchlist)) != NULL) { + ISC_LIST_UNLINK(conf->searchlist, searchentry, link); + isc_mem_put(conf->mctx, searchentry, sizeof(*searchentry)); + } + + while ((address = ISC_LIST_HEAD(conf->nameservers)) != NULL) { + ISC_LIST_UNLINK(conf->nameservers, address, link); + isc_mem_put(conf->mctx, address, sizeof(*address)); + } + + if (conf->domainname != NULL) + isc_mem_free(conf->mctx, conf->domainname); + + for (i = 0; i < RESCONFMAXSEARCH; i++) { + if (conf->search[i] != NULL) + isc_mem_free(conf->mctx, conf->search[i]); + } + + isc_mem_put(conf->mctx, conf, sizeof(*conf)); + + *confp = NULL; +} + +isc_sockaddrlist_t * +irs_resconf_getnameservers(irs_resconf_t *conf) { + REQUIRE(IRS_RESCONF_VALID(conf)); + + return (&conf->nameservers); +} + +irs_resconf_searchlist_t * +irs_resconf_getsearchlist(irs_resconf_t *conf) { + REQUIRE(IRS_RESCONF_VALID(conf)); + + return (&conf->searchlist); +} + +unsigned int +irs_resconf_getndots(irs_resconf_t *conf) { + REQUIRE(IRS_RESCONF_VALID(conf)); + + return ((unsigned int)conf->ndots); +} diff --git a/lib/irs/version.c b/lib/irs/version.c new file mode 100644 index 0000000..b27de99 --- /dev/null +++ b/lib/irs/version.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: version.c,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +/*! \file */ + +#include + +const char irs_version[] = VERSION; + +const unsigned int irs_libinterface = LIBINTERFACE; +const unsigned int irs_librevision = LIBREVISION; +const unsigned int irs_libage = LIBAGE; diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in index d831fcf..d92c0b8 100644 --- a/lib/isc/Makefile.in +++ b/lib/isc/Makefile.in @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.96.50.6 2010-06-09 01:52:54 marka Exp $ +# $Id: Makefile.in,v 1.109 2010-06-09 01:43:09 marka Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -27,8 +27,8 @@ CINCLUDES = -I${srcdir}/unix/include \ -I${srcdir}/@ISC_THREAD_DIR@/include \ -I${srcdir}/@ISC_ARCH_DIR@/include \ -I./include \ - -I${srcdir}/include -CDEFINES = + -I${srcdir}/include @ISC_OPENSSL_INC@ +CDEFINES = @USE_OPENSSL@ CWARNINGS = # Alphabetically @@ -39,7 +39,6 @@ UNIXOBJS = @ISC_ISCIPV6_O@ \ unix/os.@O@ unix/resource.@O@ unix/socket.@O@ unix/stdio.@O@ \ unix/stdtime.@O@ unix/strerror.@O@ unix/syslog.@O@ unix/time.@O@ - NLSOBJS = nls/msgcat.@O@ THREADOPTOBJS = @ISC_THREAD_DIR@/condition.@O@ @ISC_THREAD_DIR@/mutex.@O@ @@ -52,8 +51,9 @@ WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \ # Alphabetically OBJS = @ISC_EXTRA_OBJS@ \ - assertions.@O@ base32.@O@ base64.@O@ bitstring.@O@ buffer.@O@ \ - bufferlist.@O@ commandline.@O@ error.@O@ event.@O@ \ + assertions.@O@ backtrace.@O@ base32.@O@ base64.@O@ \ + bitstring.@O@ buffer.@O@ bufferlist.@O@ commandline.@O@ \ + error.@O@ event.@O@ \ hash.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \ httpd.@O@ inet_aton.@O@ iterated_hash.@O@ \ lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \ @@ -64,11 +64,12 @@ OBJS = @ISC_EXTRA_OBJS@ \ serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ stats.@O@ \ string.@O@ strtoul.@O@ symtab.@O@ task.@O@ taskpool.@O@ \ timer.@O@ version.@O@ ${UNIXOBJS} ${NLSOBJS} ${THREADOBJS} +SYMTBLOBJS = backtrace-emptytbl.@O@ # Alphabetically SRCS = @ISC_EXTRA_SRCS@ \ - assertions.c base32.c base64.c bitstring.c buffer.c \ - bufferlist.c commandline.c error.c event.c \ + assertions.c backtrace.c base32.c base64.c bitstring.c \ + buffer.c bufferlist.c commandline.c error.c event.c \ heap.c hex.c hmacmd5.c hmacsha.c \ httpd.c inet_aton.c iterated_hash.c \ lex.c lfsr.c lib.c log.c \ @@ -77,7 +78,7 @@ SRCS = @ISC_EXTRA_SRCS@ \ parseint.c portset.c quota.c radix.c random.c \ ratelimiter.c refcount.c region.c result.c rwlock.c \ serial.c sha1.c sha2.c sockaddr.c stats.c string.c strtoul.c \ - symtab.c task.c taskpool.c timer.c version.c + symtab.c symtbl-empty.c task.c taskpool.c timer.c version.c LIBS = @LIBS@ @@ -98,17 +99,27 @@ version.@O@: version.c -DLIBAGE=${LIBAGE} \ -c ${srcdir}/version.c -libisc.@SA@: ${OBJS} +libisc.@SA@: ${OBJS} ${SYMTBLOBJS} + ${AR} ${ARFLAGS} $@ ${OBJS} ${SYMTBLOBJS} + ${RANLIB} $@ + +libisc-nosymtbl.@SA@: ${OBJS} ${AR} ${ARFLAGS} $@ ${OBJS} ${RANLIB} $@ -libisc.la: ${OBJS} +libisc.la: ${OBJS} ${SYMTBLOBJS} ${LIBTOOL_MODE_LINK} \ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc.la -rpath ${libdir} \ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${SYMTBLOBJS} ${LIBS} + +libisc-nosymtbl.la: ${OBJS} + ${LIBTOOL_MODE_LINK} \ + ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-nosymtbl.la -rpath ${libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ ${OBJS} ${LIBS} -timestamp: libisc.@A@ +timestamp: libisc.@A@ libisc-nosymtbl.@A@ touch timestamp installdirs: @@ -118,4 +129,5 @@ install:: timestamp installdirs ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libisc.@A@ ${DESTDIR}${libdir} clean distclean:: - rm -f libisc.@A@ libisc.la timestamp + rm -f libisc.@A@ libisc-nosymtbl.@A@ libisc.la \ + libisc-nosymtbl.la timestamp diff --git a/lib/isc/alpha/include/isc/atomic.h b/lib/isc/alpha/include/isc/atomic.h index bb4f1ad..012c955 100644 --- a/lib/isc/alpha/include/isc/atomic.h +++ b/lib/isc/alpha/include/isc/atomic.h @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: atomic.h,v 1.5.332.2 2009-04-08 06:47:32 tbox Exp $ */ +/* $Id: atomic.h,v 1.7 2009-04-08 06:48:23 tbox Exp $ */ /* * This code was written based on FreeBSD's kernel source whose copyright diff --git a/lib/isc/api b/lib/isc/api index e1f7b71..b91b130 100644 --- a/lib/isc/api +++ b/lib/isc/api @@ -1,3 +1,3 @@ -LIBINTERFACE = 54 -LIBREVISION = 1 -LIBAGE = 4 +LIBINTERFACE = 81 +LIBREVISION = 2 +LIBAGE = 0 diff --git a/lib/isc/app_api.c b/lib/isc/app_api.c new file mode 100644 index 0000000..b2a2f14 --- /dev/null +++ b/lib/isc/app_api.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: app_api.c,v 1.5 2009-09-02 23:48:02 tbox Exp $ */ + +#include + +#include + +#include +#include +#include +#include +#include + +static isc_mutex_t createlock; +static isc_once_t once = ISC_ONCE_INIT; +static isc_appctxcreatefunc_t appctx_createfunc = NULL; + +#define ISCAPI_APPMETHODS_VALID(m) ISC_MAGIC_VALID(m, ISCAPI_APPMETHODS_MAGIC) + +static void +initialize(void) { + RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS); +} + +isc_result_t +isc_app_register(isc_appctxcreatefunc_t createfunc) { + isc_result_t result = ISC_R_SUCCESS; + + RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); + + LOCK(&createlock); + if (appctx_createfunc == NULL) + appctx_createfunc = createfunc; + else + result = ISC_R_EXISTS; + UNLOCK(&createlock); + + return (result); +} + +isc_result_t +isc_appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp) { + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(appctx_createfunc != NULL); + result = (*appctx_createfunc)(mctx, ctxp); + + UNLOCK(&createlock); + + return (result); +} + +void +isc_appctx_destroy(isc_appctx_t **ctxp) { + REQUIRE(ctxp != NULL && ISCAPI_APPCTX_VALID(*ctxp)); + + (*ctxp)->methods->ctxdestroy(ctxp); + + ENSURE(*ctxp == NULL); +} + +isc_result_t +isc_app_ctxstart(isc_appctx_t *ctx) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + + return (ctx->methods->ctxstart(ctx)); +} + +isc_result_t +isc_app_ctxrun(isc_appctx_t *ctx) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + + return (ctx->methods->ctxrun(ctx)); +} + +isc_result_t +isc_app_ctxsuspend(isc_appctx_t *ctx) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + + return (ctx->methods->ctxsuspend(ctx)); +} + +isc_result_t +isc_app_ctxshutdown(isc_appctx_t *ctx) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + + return (ctx->methods->ctxshutdown(ctx)); +} + +void +isc_app_ctxfinish(isc_appctx_t *ctx) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + + ctx->methods->ctxfinish(ctx); +} + +void +isc_appctx_settaskmgr(isc_appctx_t *ctx, isc_taskmgr_t *taskmgr) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + REQUIRE(taskmgr != NULL); + + ctx->methods->settaskmgr(ctx, taskmgr); +} + +void +isc_appctx_setsocketmgr(isc_appctx_t *ctx, isc_socketmgr_t *socketmgr) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + REQUIRE(socketmgr != NULL); + + ctx->methods->setsocketmgr(ctx, socketmgr); +} + +void +isc_appctx_settimermgr(isc_appctx_t *ctx, isc_timermgr_t *timermgr) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + REQUIRE(timermgr != NULL); + + ctx->methods->settimermgr(ctx, timermgr); +} diff --git a/lib/isc/assertions.c b/lib/isc/assertions.c index b98d61d..fe082b7 100644 --- a/lib/isc/assertions.c +++ b/lib/isc/assertions.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1997-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: assertions.c,v 1.23 2008-10-15 23:47:31 tbox Exp $ */ +/* $Id: assertions.c,v 1.26 2009-09-29 15:06:07 fdupont Exp $ */ /*! \file */ @@ -25,29 +25,47 @@ #include #include +#include #include +#include + +/* + * The maximum number of stack frames to dump on assertion failure. + */ +#ifndef BACKTRACE_MAXFRAME +#define BACKTRACE_MAXFRAME 128 +#endif /*% * Forward. */ -/* coverity[+kill] */ static void default_callback(const char *, int, isc_assertiontype_t, const char *); +static isc_assertioncallback_t isc_assertion_failed_cb = default_callback; + /*% * Public. */ -LIBISC_EXTERNAL_DATA isc_assertioncallback_t isc_assertion_failed = - default_callback; +/*% assertion failed handler */ +/* coverity[+kill] */ +void +isc_assertion_failed(const char *file, int line, isc_assertiontype_t type, + const char *cond) +{ + isc_assertion_failed_cb(file, line, type, cond); + abort(); + /* NOTREACHED */ +} /*% Set callback. */ void isc_assertion_setcallback(isc_assertioncallback_t cb) { if (cb == NULL) - isc_assertion_failed = default_callback; + isc_assertion_failed_cb = default_callback; else - isc_assertion_failed = cb; + isc_assertion_failed_cb = cb; } /*% Type to Text */ @@ -87,11 +105,35 @@ static void default_callback(const char *file, int line, isc_assertiontype_t type, const char *cond) { - fprintf(stderr, "%s:%d: %s(%s) %s.\n", + void *tracebuf[BACKTRACE_MAXFRAME]; + int i, nframes; + const char *logsuffix = "."; + const char *fname; + isc_result_t result; + + result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME, &nframes); + if (result == ISC_R_SUCCESS && nframes > 0) + logsuffix = ", back trace"; + + fprintf(stderr, "%s:%d: %s(%s) %s%s\n", file, line, isc_assertion_typetotext(type), cond, isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, - ISC_MSG_FAILED, "failed")); + ISC_MSG_FAILED, "failed"), logsuffix); + if (result == ISC_R_SUCCESS) { + for (i = 0; i < nframes; i++) { + unsigned long offset; + + fname = NULL; + result = isc_backtrace_getsymbol(tracebuf[i], &fname, + &offset); + if (result == ISC_R_SUCCESS) { + fprintf(stderr, "#%d %p in %s()+0x%lx\n", i, + tracebuf[i], fname, offset); + } else { + fprintf(stderr, "#%d %p in ??\n", i, + tracebuf[i]); + } + } + } fflush(stderr); - abort(); - /* NOTREACHED */ } diff --git a/lib/isc/backtrace-emptytbl.c b/lib/isc/backtrace-emptytbl.c new file mode 100644 index 0000000..2743030 --- /dev/null +++ b/lib/isc/backtrace-emptytbl.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: backtrace-emptytbl.c,v 1.3 2009-09-01 20:13:44 each Exp $ */ + +/*! \file */ + +/* + * This file defines an empty (default) symbol table used in backtrace.c + * If the application wants to have a complete symbol table, it should redefine + * isc__backtrace_symtable with the complete table in some way, and link the + * version of the library not including this definition + * (e.g. libisc-nosymbol.a). + */ + +#include + +#include + +const int isc__backtrace_nsymbols = 0; +const isc_backtrace_symmap_t isc__backtrace_symtable[] = { { NULL, "" } }; diff --git a/lib/isc/backtrace.c b/lib/isc/backtrace.c new file mode 100644 index 0000000..7b5ddfe --- /dev/null +++ b/lib/isc/backtrace.c @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: backtrace.c,v 1.3 2009-09-02 23:48:02 tbox Exp $ */ + +/*! \file */ + +#include "config.h" + +#include +#include +#ifdef HAVE_LIBCTRACE +#include +#endif + +#include +#include +#include + +#ifdef ISC_PLATFORM_USEBACKTRACE +/* + * Getting a back trace of a running process is tricky and highly platform + * dependent. Our current approach is as follows: + * 1. If the system library supports the "backtrace()" function, use it. + * 2. Otherwise, if the compiler is gcc and the architecture is x86_64 or IA64, + * then use gcc's (hidden) Unwind_Backtrace() function. Note that this + * function doesn't work for C programs on many other architectures. + * 3. Otherwise, if the architecture x86 or x86_64, try to unwind the stack + * frame following frame pointers. This assumes the executable binary + * compiled with frame pointers; this is not always true for x86_64 (rather, + * compiler optimizations often disable frame pointers). The validation + * checks in getnextframeptr() hopefully rejects bogus values stored in + * the RBP register in such a case. If the backtrace function itself crashes + * due to this problem, the whole package should be rebuilt with + * --disable-backtrace. + */ +#ifdef HAVE_LIBCTRACE +#define BACKTRACE_LIBC +#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__ia64__)) +#define BACKTRACE_GCC +#elif defined(__x86_64__) || defined(__i386__) +#define BACKTRACE_X86STACK +#else +#define BACKTRACE_DISABLED +#endif /* HAVE_LIBCTRACE */ +#else /* !ISC_PLATFORM_USEBACKTRACE */ +#define BACKTRACE_DISABLED +#endif /* ISC_PLATFORM_USEBACKTRACE */ + +#ifdef BACKTRACE_LIBC +isc_result_t +isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) { + int n; + + /* + * Validate the arguments: intentionally avoid using REQUIRE(). + * See notes in backtrace.h. + */ + if (addrs == NULL || nframes == NULL) + return (ISC_R_FAILURE); + + /* + * backtrace(3) includes this function itself in the address array, + * which should be eliminated from the returned sequence. + */ + n = backtrace(addrs, maxaddrs); + if (n < 2) + return (ISC_R_NOTFOUND); + n--; + memmove(addrs, &addrs[1], sizeof(void *) * n); + *nframes = n; + return (ISC_R_SUCCESS); +} +#elif defined(BACKTRACE_GCC) +extern int _Unwind_Backtrace(void* fn, void* a); +extern void* _Unwind_GetIP(void* ctx); + +typedef struct { + void **result; + int max_depth; + int skip_count; + int count; +} trace_arg_t; + +static int +btcallback(void *uc, void *opq) { + trace_arg_t *arg = (trace_arg_t *)opq; + + if (arg->skip_count > 0) + arg->skip_count--; + else + arg->result[arg->count++] = (void *)_Unwind_GetIP(uc); + if (arg->count == arg->max_depth) + return (5); /* _URC_END_OF_STACK */ + + return (0); /* _URC_NO_REASON */ +} + +isc_result_t +isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) { + trace_arg_t arg; + + /* Argument validation: see above. */ + if (addrs == NULL || nframes == NULL) + return (ISC_R_FAILURE); + + arg.skip_count = 1; + arg.result = addrs; + arg.max_depth = maxaddrs; + arg.count = 0; + _Unwind_Backtrace(btcallback, &arg); + + *nframes = arg.count; + + return (ISC_R_SUCCESS); +} +#elif defined(BACKTRACE_X86STACK) +#ifdef __x86_64__ +static unsigned long +getrbp() { + __asm("movq %rbp, %rax\n"); +} +#endif + +static void ** +getnextframeptr(void **sp) { + void **newsp = (void **)*sp; + + /* + * Perform sanity check for the new frame pointer, derived from + * google glog. This can actually be bogus depending on compiler. + */ + + /* prohibit the stack frames from growing downwards */ + if (newsp <= sp) + return (NULL); + + /* A heuristics to reject "too large" frame: this actually happened. */ + if ((char *)newsp - (char *)sp > 100000) + return (NULL); + + /* + * Not sure if other checks used in glog are needed at this moment. + * For our purposes we don't have to consider non-contiguous frames, + * for example. + */ + + return (newsp); +} + +isc_result_t +isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) { + int i = 0; + void **sp; + + /* Argument validation: see above. */ + if (addrs == NULL || nframes == NULL) + return (ISC_R_FAILURE); + +#ifdef __x86_64__ + sp = (void **)getrbp(); + if (sp == NULL) + return (ISC_R_NOTFOUND); + /* + * sp is the frame ptr of this function itself due to the call to + * getrbp(), so need to unwind one frame for consistency. + */ + sp = getnextframeptr(sp); +#else + /* + * i386: the frame pointer is stored 2 words below the address for the + * first argument. Note that the body of this function cannot be + * inlined since it depends on the address of the function argument. + */ + sp = (void **)&addrs - 2; +#endif + + while (sp != NULL && i < maxaddrs) { + addrs[i++] = *(sp + 1); + sp = getnextframeptr(sp); + } + + *nframes = i; + + return (ISC_R_SUCCESS); +} +#elif defined(BACKTRACE_DISABLED) +isc_result_t +isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) { + /* Argument validation: see above. */ + if (addrs == NULL || nframes == NULL) + return (ISC_R_FAILURE); + + UNUSED(maxaddrs); + + return (ISC_R_NOTIMPLEMENTED); +} +#endif + +isc_result_t +isc_backtrace_getsymbolfromindex(int index, const void **addrp, + const char **symbolp) +{ + REQUIRE(addrp != NULL && *addrp == NULL); + REQUIRE(symbolp != NULL && *symbolp == NULL); + + if (index < 0 || index >= isc__backtrace_nsymbols) + return (ISC_R_RANGE); + + *addrp = isc__backtrace_symtable[index].addr; + *symbolp = isc__backtrace_symtable[index].symbol; + return (ISC_R_SUCCESS); +} + +static int +symtbl_compare(const void *addr, const void *entryarg) { + const isc_backtrace_symmap_t *entry = entryarg; + const isc_backtrace_symmap_t *end = + &isc__backtrace_symtable[isc__backtrace_nsymbols - 1]; + + if (isc__backtrace_nsymbols == 1 || entry == end) { + if (addr >= entry->addr) { + /* + * If addr is equal to or larger than that of the last + * entry of the table, we cannot be sure if this is + * within a valid range so we consider it valid. + */ + return (0); + } + return (-1); + } + + /* entry + 1 is a valid entry from now on. */ + if (addr < entry->addr) + return (-1); + else if (addr >= (entry + 1)->addr) + return (1); + return (0); +} + +isc_result_t +isc_backtrace_getsymbol(const void *addr, const char **symbolp, + unsigned long *offsetp) +{ + isc_result_t result = ISC_R_SUCCESS; + isc_backtrace_symmap_t *found; + + /* + * Validate the arguments: intentionally avoid using REQUIRE(). + * See notes in backtrace.h. + */ + if (symbolp == NULL || *symbolp != NULL || offsetp == NULL) + return (ISC_R_FAILURE); + + if (isc__backtrace_nsymbols < 1) + return (ISC_R_NOTFOUND); + + /* + * Search the table for the entry that meets: + * entry.addr <= addr < next_entry.addr. + */ + found = bsearch(addr, isc__backtrace_symtable, isc__backtrace_nsymbols, + sizeof(isc__backtrace_symtable[0]), symtbl_compare); + if (found == NULL) + result = ISC_R_NOTFOUND; + else { + *symbolp = found->symbol; + *offsetp = (const char *)addr - (char *)found->addr; + } + + return (result); +} diff --git a/lib/isc/base32.c b/lib/isc/base32.c index 5e5cbd9..7621920 100644 --- a/lib/isc/base32.c +++ b/lib/isc/base32.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: base32.c,v 1.3.116.3 2009-10-21 01:22:47 each Exp $ */ +/* $Id: base32.c,v 1.6 2009-10-21 01:22:29 each Exp $ */ /*! \file */ diff --git a/lib/isc/base64.c b/lib/isc/base64.c index 858525f..ee34c3c 100644 --- a/lib/isc/base64.c +++ b/lib/isc/base64.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: base64.c,v 1.32.332.2 2009-10-21 23:47:20 tbox Exp $ */ +/* $Id: base64.c,v 1.34 2009-10-21 23:48:05 tbox Exp $ */ /*! \file */ diff --git a/lib/isc/entropy.c b/lib/isc/entropy.c index af8757f..8d273d2 100644 --- a/lib/isc/entropy.c +++ b/lib/isc/entropy.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: entropy.c,v 1.18.332.4 2010-08-10 23:46:54 tbox Exp $ */ +/* $Id: entropy.c,v 1.22 2010-08-10 23:48:19 tbox Exp $ */ /*! \file * \brief diff --git a/lib/isc/hash.c b/lib/isc/hash.c index 7c0fcea..44975e7 100644 --- a/lib/isc/hash.c +++ b/lib/isc/hash.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: hash.c,v 1.13.332.3 2009-05-07 23:47:12 tbox Exp $ */ +/* $Id: hash.c,v 1.16 2009-09-01 00:22:28 jinmei Exp $ */ /*! \file * Some portion of this code was derived from universal hash function @@ -194,8 +194,12 @@ isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy, hctx->vectorlen = vlen; hctx->rndvector = rv; +#ifdef BIND9 if (entropy != NULL) isc_entropy_attach(entropy, &hctx->entropy); +#else + UNUSED(entropy); +#endif *hctxp = hctx; return (ISC_R_SUCCESS); @@ -236,18 +240,22 @@ isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit) { void isc_hash_ctxinit(isc_hash_t *hctx) { - isc_result_t result; - LOCK(&hctx->lock); if (hctx->initialized == ISC_TRUE) goto out; if (hctx->entropy) { +#ifdef BIND9 + isc_result_t result; + result = isc_entropy_getdata(hctx->entropy, hctx->rndvector, hctx->vectorlen, NULL, 0); INSIST(result == ISC_R_SUCCESS); +#else + INSIST(0); +#endif } else { isc_uint32_t pr; unsigned int i, copylen; @@ -293,6 +301,7 @@ static void destroy(isc_hash_t **hctxp) { isc_hash_t *hctx; isc_mem_t *mctx; + unsigned char canary0[4], canary1[4]; REQUIRE(hctxp != NULL && *hctxp != NULL); hctx = *hctxp; @@ -303,8 +312,10 @@ destroy(isc_hash_t **hctxp) { isc_refcount_destroy(&hctx->refcnt); mctx = hctx->mctx; +#ifdef BIND9 if (hctx->entropy != NULL) isc_entropy_detach(&hctx->entropy); +#endif if (hctx->rndvector != NULL) isc_mem_put(mctx, hctx->rndvector, hctx->vectorlen); @@ -312,7 +323,10 @@ destroy(isc_hash_t **hctxp) { DESTROYLOCK(&hctx->lock); + memcpy(canary0, hctx + 1, sizeof(canary0)); memset(hctx, 0, sizeof(isc_hash_t)); + memcpy(canary1, hctx + 1, sizeof(canary1)); + INSIST(memcmp(canary0, canary1, sizeof(canary0)) == 0); isc_mem_put(mctx, hctx, sizeof(isc_hash_t)); isc_mem_detach(&mctx); } diff --git a/lib/isc/heap.c b/lib/isc/heap.c index 68f8ba8..4dead3f 100644 --- a/lib/isc/heap.c +++ b/lib/isc/heap.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: heap.c,v 1.37.240.3 2010-02-04 23:47:46 tbox Exp $ */ +/* $Id: heap.c,v 1.39 2010-02-04 23:49:13 tbox Exp $ */ /*! \file * Heap implementation of priority queues adapted from the following: diff --git a/lib/isc/hmacmd5.c b/lib/isc/hmacmd5.c index b1d5906..10e87c9 100644 --- a/lib/isc/hmacmd5.c +++ b/lib/isc/hmacmd5.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: hmacmd5.c,v 1.14 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: hmacmd5.c,v 1.16 2009-02-06 23:47:42 tbox Exp $ */ /*! \file * This code implements the HMAC-MD5 keyed hash algorithm @@ -27,10 +27,40 @@ #include #include #include +#include #include #include #include +#ifdef ISC_PLATFORM_OPENSSLHASH + +void +isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key, + unsigned int len) +{ + HMAC_Init(ctx, (const void *) key, (int) len, EVP_md5()); +} + +void +isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) { + HMAC_CTX_cleanup(ctx); +} + +void +isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf, + unsigned int len) +{ + HMAC_Update(ctx, buf, (int) len); +} + +void +isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) { + HMAC_Final(ctx, digest, NULL); + HMAC_CTX_cleanup(ctx); +} + +#else + #define PADLEN 64 #define IPAD 0x36 #define OPAD 0x5C @@ -98,6 +128,7 @@ isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) { isc_md5_final(&ctx->md5ctx, digest); isc_hmacmd5_invalidate(ctx); } +#endif /* !ISC_PLATFORM_OPENSSLHASH */ /*! * Verify signature - finalize MD5 operation and reapply MD5, then diff --git a/lib/isc/hmacsha.c b/lib/isc/hmacsha.c index 9f27163..125672d 100644 --- a/lib/isc/hmacsha.c +++ b/lib/isc/hmacsha.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2005-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: hmacsha.c,v 1.8 2007-08-27 03:27:53 marka Exp $ */ +/* $Id: hmacsha.c,v 1.10 2009-02-06 23:47:42 tbox Exp $ */ /* * This code implements the HMAC-SHA1, HMAC-SHA224, HMAC-SHA256, HMAC-SHA384 @@ -26,12 +26,172 @@ #include #include +#include #include #include #include #include #include +#ifdef ISC_PLATFORM_OPENSSLHASH + +void +isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key, + unsigned int len) +{ + HMAC_Init(ctx, (const void *) key, (int) len, EVP_sha1()); +} + +void +isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx) { + HMAC_CTX_cleanup(ctx); +} + +void +isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf, + unsigned int len) +{ + HMAC_Update(ctx, buf, (int) len); +} + +void +isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA1_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA1_DIGESTLENGTH); + + HMAC_Final(ctx, newdigest, NULL); + HMAC_CTX_cleanup(ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +void +isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key, + unsigned int len) +{ + HMAC_Init(ctx, (const void *) key, (int) len, EVP_sha224()); +} + +void +isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx) { + HMAC_CTX_cleanup(ctx); +} + +void +isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf, + unsigned int len) +{ + HMAC_Update(ctx, buf, (int) len); +} + +void +isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA224_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA224_DIGESTLENGTH); + + HMAC_Final(ctx, newdigest, NULL); + HMAC_CTX_cleanup(ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +void +isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key, + unsigned int len) +{ + HMAC_Init(ctx, (const void *) key, (int) len, EVP_sha256()); +} + +void +isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx) { + HMAC_CTX_cleanup(ctx); +} + +void +isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf, + unsigned int len) +{ + HMAC_Update(ctx, buf, (int) len); +} + +void +isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA256_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA256_DIGESTLENGTH); + + HMAC_Final(ctx, newdigest, NULL); + HMAC_CTX_cleanup(ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +void +isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key, + unsigned int len) +{ + HMAC_Init(ctx, (const void *) key, (int) len, EVP_sha384()); +} + +void +isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx) { + HMAC_CTX_cleanup(ctx); +} + +void +isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf, + unsigned int len) +{ + HMAC_Update(ctx, buf, (int) len); +} + +void +isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA384_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA384_DIGESTLENGTH); + + HMAC_Final(ctx, newdigest, NULL); + HMAC_CTX_cleanup(ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +void +isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key, + unsigned int len) +{ + HMAC_Init(ctx, (const void *) key, (int) len, EVP_sha512()); +} + +void +isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx) { + HMAC_CTX_cleanup(ctx); +} + +void +isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf, + unsigned int len) +{ + HMAC_Update(ctx, buf, (int) len); +} + +void +isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA512_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA512_DIGESTLENGTH); + + HMAC_Final(ctx, newdigest, NULL); + HMAC_CTX_cleanup(ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +#else + #define IPAD 0x36 #define OPAD 0x5C @@ -105,19 +265,6 @@ isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) { } /* - * Verify signature - finalize SHA1 operation and reapply SHA1, then - * compare to the supplied digest. - */ -isc_boolean_t -isc_hmacsha1_verify(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) { - unsigned char newdigest[ISC_SHA1_DIGESTLENGTH]; - - REQUIRE(len <= ISC_SHA1_DIGESTLENGTH); - isc_hmacsha1_sign(ctx, newdigest, ISC_SHA1_DIGESTLENGTH); - return (ISC_TF(memcmp(digest, newdigest, len) == 0)); -} - -/* * Start HMAC-SHA224 process. Initialize an sha224 context and digest the key. */ void @@ -185,19 +332,6 @@ isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) { } /* - * Verify signature - finalize SHA224 operation and reapply SHA224, then - * compare to the supplied digest. - */ -isc_boolean_t -isc_hmacsha224_verify(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) { - unsigned char newdigest[ISC_SHA224_DIGESTLENGTH]; - - REQUIRE(len <= ISC_SHA224_DIGESTLENGTH); - isc_hmacsha224_sign(ctx, newdigest, ISC_SHA224_DIGESTLENGTH); - return (ISC_TF(memcmp(digest, newdigest, len) == 0)); -} - -/* * Start HMAC-SHA256 process. Initialize an sha256 context and digest the key. */ void @@ -265,19 +399,6 @@ isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) { } /* - * Verify signature - finalize SHA256 operation and reapply SHA256, then - * compare to the supplied digest. - */ -isc_boolean_t -isc_hmacsha256_verify(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) { - unsigned char newdigest[ISC_SHA256_DIGESTLENGTH]; - - REQUIRE(len <= ISC_SHA256_DIGESTLENGTH); - isc_hmacsha256_sign(ctx, newdigest, ISC_SHA256_DIGESTLENGTH); - return (ISC_TF(memcmp(digest, newdigest, len) == 0)); -} - -/* * Start HMAC-SHA384 process. Initialize an sha384 context and digest the key. */ void @@ -345,19 +466,6 @@ isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) { } /* - * Verify signature - finalize SHA384 operation and reapply SHA384, then - * compare to the supplied digest. - */ -isc_boolean_t -isc_hmacsha384_verify(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) { - unsigned char newdigest[ISC_SHA384_DIGESTLENGTH]; - - REQUIRE(len <= ISC_SHA384_DIGESTLENGTH); - isc_hmacsha384_sign(ctx, newdigest, ISC_SHA384_DIGESTLENGTH); - return (ISC_TF(memcmp(digest, newdigest, len) == 0)); -} - -/* * Start HMAC-SHA512 process. Initialize an sha512 context and digest the key. */ void @@ -423,6 +531,59 @@ isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) { memcpy(digest, newdigest, len); memset(newdigest, 0, sizeof(newdigest)); } +#endif /* !ISC_PLATFORM_OPENSSLHASH */ + +/* + * Verify signature - finalize SHA1 operation and reapply SHA1, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha1_verify(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA1_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA1_DIGESTLENGTH); + isc_hmacsha1_sign(ctx, newdigest, ISC_SHA1_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} + +/* + * Verify signature - finalize SHA224 operation and reapply SHA224, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha224_verify(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA224_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA224_DIGESTLENGTH); + isc_hmacsha224_sign(ctx, newdigest, ISC_SHA224_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} + +/* + * Verify signature - finalize SHA256 operation and reapply SHA256, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha256_verify(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA256_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA256_DIGESTLENGTH); + isc_hmacsha256_sign(ctx, newdigest, ISC_SHA256_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} + +/* + * Verify signature - finalize SHA384 operation and reapply SHA384, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha384_verify(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA384_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA384_DIGESTLENGTH); + isc_hmacsha384_sign(ctx, newdigest, ISC_SHA384_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} /* * Verify signature - finalize SHA512 operation and reapply SHA512, then diff --git a/lib/isc/httpd.c b/lib/isc/httpd.c index b653f79..81f118e 100644 --- a/lib/isc/httpd.c +++ b/lib/isc/httpd.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: httpd.c,v 1.16.64.2 2010-02-04 23:47:46 tbox Exp $ */ +/* $Id: httpd.c,v 1.20 2010-11-16 05:38:31 marka Exp $ */ /*! \file */ diff --git a/lib/isc/ia64/include/isc/atomic.h b/lib/isc/ia64/include/isc/atomic.h index 466cddb..11c9706 100644 --- a/lib/isc/ia64/include/isc/atomic.h +++ b/lib/isc/ia64/include/isc/atomic.h @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: atomic.h,v 1.4.326.3 2009-06-24 02:21:28 marka Exp $ */ +/* $Id: atomic.h,v 1.7 2009-06-24 02:22:50 marka Exp $ */ #ifndef ISC_ATOMIC_H #define ISC_ATOMIC_H 1 diff --git a/lib/isc/include/isc/Makefile.in b/lib/isc/include/isc/Makefile.in index c1d71f4..12c09cd 100644 --- a/lib/isc/include/isc/Makefile.in +++ b/lib/isc/include/isc/Makefile.in @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.64.12.2 2009-02-12 23:47:22 tbox Exp $ +# $Id: Makefile.in,v 1.68 2009-12-05 23:31:41 each Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -26,15 +26,15 @@ top_srcdir = @top_srcdir@ # machine generated. The latter are handled specially in the # install target below. # -HEADERS = app.h assertions.h base64.h bitstring.h boolean.h buffer.h \ - bufferlist.h commandline.h entropy.h error.h event.h \ +HEADERS = app.h assertions.h base64.h bind9.h bitstring.h boolean.h \ + buffer.h bufferlist.h commandline.h entropy.h error.h event.h \ eventclass.h file.h formatcheck.h fsaccess.h \ hash.h heap.h hex.h hmacmd5.h \ httpd.h \ interfaceiter.h @ISC_IPV6_H@ iterated_hash.h lang.h lex.h \ lfsr.h lib.h list.h log.h \ - magic.h md5.h mem.h msgcat.h msgs.h \ - mutexblock.h netaddr.h ondestroy.h os.h parseint.h \ + magic.h md5.h mem.h msgcat.h msgs.h mutexblock.h \ + namespace.h netaddr.h ondestroy.h os.h parseint.h \ print.h quota.h radix.h random.h ratelimiter.h \ refcount.h region.h resource.h \ result.h resultclass.h rwlock.h serial.h sha1.h sha2.h \ diff --git a/lib/isc/include/isc/app.h b/lib/isc/include/isc/app.h index 0552758..ac8669f 100644 --- a/lib/isc/include/isc/app.h +++ b/lib/isc/include/isc/app.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: app.h,v 1.8 2007-06-19 23:47:18 tbox Exp $ */ +/* $Id: app.h,v 1.11 2009-09-02 23:48:03 tbox Exp $ */ #ifndef ISC_APP_H #define ISC_APP_H 1 @@ -54,12 +54,23 @@ * Use of this module is not required. In particular, isc_app_start() is * NOT an ISC library initialization routine. * + * This module also supports per-thread 'application contexts'. With this + * mode, a thread-based application will have a separate context, in which + * it uses other ISC library services such as tasks or timers. Signals are + * not caught in this mode, so that the application can handle the signals + * in its preferred way. + * * \li MP: * Clients must ensure that isc_app_start(), isc_app_run(), and * isc_app_finish() are called at most once. isc_app_shutdown() * is safe to use by any thread (provided isc_app_start() has been * called previously). * + * The same note applies to isc_app_ctxXXX() functions, but in this case + * it's a per-thread restriction. For example, a thread with an + * application context must ensure that isc_app_ctxstart() with the + * context is called at most once. + * * \li Reliability: * No anticipated impact. * @@ -75,17 +86,64 @@ #include #include +#include #include +/*** + *** Types + ***/ + typedef isc_event_t isc_appevent_t; #define ISC_APPEVENT_FIRSTEVENT (ISC_EVENTCLASS_APP + 0) #define ISC_APPEVENT_SHUTDOWN (ISC_EVENTCLASS_APP + 1) #define ISC_APPEVENT_LASTEVENT (ISC_EVENTCLASS_APP + 65535) +/*% + * app module methods. Only app driver implementations use this structure. + * Other clients should use the top-level interfaces (i.e., isc_app_xxx + * functions). magic must be ISCAPI_APPMETHODS_MAGIC. + */ +typedef struct isc_appmethods { + void (*ctxdestroy)(isc_appctx_t **ctxp); + isc_result_t (*ctxstart)(isc_appctx_t *ctx); + isc_result_t (*ctxrun)(isc_appctx_t *ctx); + isc_result_t (*ctxsuspend)(isc_appctx_t *ctx); + isc_result_t (*ctxshutdown)(isc_appctx_t *ctx); + void (*ctxfinish)(isc_appctx_t *ctx); + void (*settaskmgr)(isc_appctx_t *ctx, + isc_taskmgr_t *timermgr); + void (*setsocketmgr)(isc_appctx_t *ctx, + isc_socketmgr_t *timermgr); + void (*settimermgr)(isc_appctx_t *ctx, + isc_timermgr_t *timermgr); +} isc_appmethods_t; + +/*% + * This structure is actually just the common prefix of an application context + * implementation's version of an isc_appctx_t. + * \brief + * Direct use of this structure by clients is forbidden. app implementations + * may change the structure. 'magic' must be ISCAPI_APPCTX_MAGIC for any + * of the isc_app_ routines to work. app implementations must maintain + * all app context invariants. + */ +struct isc_appctx { + unsigned int impmagic; + unsigned int magic; + isc_appmethods_t *methods; +}; + +#define ISCAPI_APPCTX_MAGIC ISC_MAGIC('A','a','p','c') +#define ISCAPI_APPCTX_VALID(c) ((c) != NULL && \ + (c)->magic == ISCAPI_APPCTX_MAGIC) + ISC_LANG_BEGINDECLS isc_result_t +isc_app_ctxstart(isc_appctx_t *ctx); + +isc_result_t isc_app_start(void); /*!< * \brief Start an ISC library application. @@ -93,6 +151,9 @@ isc_app_start(void); * Notes: * This call should be made before any other ISC library call, and as * close to the beginning of the application as possible. + * + * Requires: + * 'ctx' is a valid application context (for app_ctxstart()). */ isc_result_t @@ -102,7 +163,7 @@ isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, * \brief Request delivery of an event when the application is run. * * Requires: - * isc_app_start() has been called. + *\li isc_app_start() has been called. * * Returns: * ISC_R_SUCCESS @@ -110,6 +171,9 @@ isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, */ isc_result_t +isc_app_ctxrun(isc_appctx_t *ctx); + +isc_result_t isc_app_run(void); /*!< * \brief Run an ISC library application. @@ -120,11 +184,12 @@ isc_app_run(void); * caller should start shutting down the application. * * Requires: - *\li isc_app_start() has been called. + *\li isc_app_[ctx]start() has been called. * * Ensures: *\li Any events requested via isc_app_onrun() will have been posted (in * FIFO order) before isc_app_run() blocks. + *\li 'ctx' is a valid application context (for app_ctxrun()). * * Returns: *\li ISC_R_SUCCESS Shutdown has been requested. @@ -132,6 +197,9 @@ isc_app_run(void); */ isc_result_t +isc_app_ctxshutdown(isc_appctx_t *ctx); + +isc_result_t isc_app_shutdown(void); /*!< * \brief Request application shutdown. @@ -141,7 +209,8 @@ isc_app_shutdown(void); * only be triggered once. * * Requires: - *\li isc_app_run() has been called. + *\li isc_app_[ctx]run() has been called. + *\li 'ctx' is a valid application context (for app_ctxshutdown()). * * Returns: *\li ISC_R_SUCCESS @@ -149,6 +218,12 @@ isc_app_shutdown(void); */ isc_result_t +isc_app_ctxsuspend(isc_appctx_t *ctx); +/*!< + * \brief This has the same behavior as isc_app_ctxsuspend(). + */ + +isc_result_t isc_app_reload(void); /*!< * \brief Request application reload. @@ -162,6 +237,9 @@ isc_app_reload(void); */ void +isc_app_ctxfinish(isc_appctx_t *ctx); + +void isc_app_finish(void); /*!< * \brief Finish an ISC library application. @@ -171,6 +249,7 @@ isc_app_finish(void); * * Requires: *\li isc_app_start() has been called. + *\li 'ctx' is a valid application context (for app_ctxfinish()). * * Ensures: *\li Any resources allocated by isc_app_start() have been released. @@ -206,6 +285,90 @@ isc_app_unblock(void); * \li isc_app_block() has been called by the same thread. */ +isc_result_t +isc_appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp); +/*!< + * \brief Create an application context. + * + * Requires: + *\li 'mctx' is a valid memory context. + *\li 'ctxp' != NULL && *ctxp == NULL. + */ + +void +isc_appctx_destroy(isc_appctx_t **ctxp); +/*!< + * \brief Destroy an application context. + * + * Requires: + *\li '*ctxp' is a valid application context. + * + * Ensures: + *\li *ctxp == NULL. + */ + +void +isc_appctx_settaskmgr(isc_appctx_t *ctx, isc_taskmgr_t *taskmgr); +/*!< + * \brief Associate a task manager with an application context. + * + * This must be done before running tasks within the application context. + * + * Requires: + *\li 'ctx' is a valid application context. + *\li 'taskmgr' is a valid task manager. + */ + +void +isc_appctx_setsocketmgr(isc_appctx_t *ctx, isc_socketmgr_t *socketmgr); +/*!< + * \brief Associate a socket manager with an application context. + * + * This must be done before handling socket events within the application + * context. + * + * Requires: + *\li 'ctx' is a valid application context. + *\li 'socketmgr' is a valid socket manager. + */ + +void +isc_appctx_settimermgr(isc_appctx_t *ctx, isc_timermgr_t *timermgr); +/*!< + * \brief Associate a socket timer with an application context. + * + * This must be done before handling timer events within the application + * context. + * + * Requires: + *\li 'ctx' is a valid application context. + *\li 'timermgr' is a valid timer manager. + */ + +#ifdef USE_APPIMPREGISTER +/*%< + * See isc_appctx_create() above. + */ +typedef isc_result_t +(*isc_appctxcreatefunc_t)(isc_mem_t *mctx, isc_appctx_t **ctxp); + +isc_result_t +isc_app_register(isc_appctxcreatefunc_t createfunc); +/*%< + * Register a new application implementation and add it to the list of + * supported implementations. This function must be called when a different + * event library is used than the one contained in the ISC library. + */ + +isc_result_t +isc__app_register(void); +/*%< + * A short cut function that specifies the application module in the ISC + * library for isc_app_register(). An application that uses the ISC library + * usually do not have to care about this function: it would call + * isc_lib_register(), which internally calls this function. + */ +#endif /* USE_APPIMPREGISTER */ ISC_LANG_ENDDECLS diff --git a/lib/isc/include/isc/assertions.h b/lib/isc/include/isc/assertions.h index 8a2ba7e..91217b8 100644 --- a/lib/isc/include/isc/assertions.h +++ b/lib/isc/include/isc/assertions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1997-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -16,7 +16,7 @@ */ /* - * $Id: assertions.h,v 1.26 2008-10-15 23:47:31 tbox Exp $ + * $Id: assertions.h,v 1.28 2009-09-29 23:48:04 tbox Exp $ */ /*! \file isc/assertions.h */ @@ -41,7 +41,9 @@ typedef void (*isc_assertioncallback_t)(const char *, int, isc_assertiontype_t, const char *); /* coverity[+kill] */ -LIBISC_EXTERNAL_DATA extern isc_assertioncallback_t isc_assertion_failed; +ISC_PLATFORM_NORETURN_PRE +void isc_assertion_failed(const char *, int, isc_assertiontype_t, + const char *) ISC_PLATFORM_NORETURN_POST; void isc_assertion_setcallback(isc_assertioncallback_t); diff --git a/lib/isc/include/isc/backtrace.h b/lib/isc/include/isc/backtrace.h new file mode 100644 index 0000000..94fee61 --- /dev/null +++ b/lib/isc/include/isc/backtrace.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: backtrace.h,v 1.2 2009-09-01 18:40:25 jinmei Exp $ */ + +/*! \file isc/backtrace.h + * \brief provide a back trace of the running process to help debug problems. + * + * This module tries to get a back trace of the process using some platform + * dependent way when available. It also manages an internal symbol table + * that maps function addresses used in the process to their textual symbols. + * This module is expected to be used to help debug when some fatal error + * happens. + * + * IMPORTANT NOTE: since the (major) intended use case of this module is + * dumping a back trace on a fatal error, normally followed by self termination, + * functions defined in this module generally doesn't employ assertion checks + * (if it did, a program bug could cause infinite recursive calls to a + * backtrace function). These functions still perform minimal checks and return + * ISC_R_FAILURE if they detect an error, but the caller should therefore be + * very careful about the use of these functions, and generally discouraged to + * use them except in an exit path. The exception is + * isc_backtrace_getsymbolfromindex(), which is expected to be used in a + * non-error-handling context and validates arguments with assertion checks. + */ + +#ifndef ISC_BACKTRACE_H +#define ISC_BACKTRACE_H 1 + +/*** + *** Imports + ***/ + +#include + +/*** + *** Types + ***/ +struct isc_backtrace_symmap { + void *addr; + const char *symbol; +}; + +extern const int isc__backtrace_nsymbols; +extern const isc_backtrace_symmap_t isc__backtrace_symtable[]; + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS +isc_result_t +isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes); +/*%< + * Get a back trace of the running process above this function itself. On + * success, addrs[i] will store the address of the call point of the i-th + * stack frame (addrs[0] is the caller of this function). *nframes will store + * the total number of frames. + * + * Requires (note that these are not ensured by assertion checks, see above): + * + *\li 'addrs' is a valid array containing at least 'maxaddrs' void * entries. + * + *\li 'nframes' must be non NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_FAILURE + *\li #ISC_R_NOTFOUND + *\li #ISC_R_NOTIMPLEMENTED + */ + +isc_result_t +isc_backtrace_getsymbolfromindex(int index, const void **addrp, + const char **symbolp); +/*%< + * Returns the content of the internal symbol table of the given index. + * On success, *addrsp and *symbolp point to the address and the symbol of + * the 'index'th entry of the table, respectively. If 'index' is not in the + * range of the symbol table, ISC_R_RANGE will be returned. + * + * Requires + * + *\li 'addrp' must be non NULL && '*addrp' == NULL. + * + *\li 'symbolp' must be non NULL && '*symbolp' == NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_RANGE + */ + +isc_result_t +isc_backtrace_getsymbol(const void *addr, const char **symbolp, + unsigned long *offsetp); +/*%< + * Searches the internal symbol table for the symbol that most matches the + * given 'addr'. On success, '*symbolp' will point to the name of function + * to which the address 'addr' belong, and '*offsetp' will store the offset + * from the function's entry address to 'addr'. + * + * Requires (note that these are not ensured by assertion checks, see above): + * + *\li 'symbolp' must be non NULL && '*symbolp' == NULL. + * + *\li 'offsetp' must be non NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_FAILURE + *\li #ISC_R_NOTFOUND + */ +ISC_LANG_ENDDECLS + +#endif /* ISC_BACKTRACE_H */ diff --git a/lib/isc/include/isc/bind9.h b/lib/isc/include/isc/bind9.h new file mode 100644 index 0000000..dd75e91 --- /dev/null +++ b/lib/isc/include/isc/bind9.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: bind9.h,v 1.2 2009-12-05 23:31:41 each Exp $ */ + +#ifndef ISC_BIND9_H +#define ISC_BIND9_H 1 + +/* + * This determines whether we are building BIND9 or using the exported + * libisc/libdns libraries. The version of this file included in the + * standard BIND9 build defines BIND9; the version included with the + * exportable libraries does not. + */ +#define BIND9 1 + +#endif /* ISC_BIND9_H */ diff --git a/lib/isc/include/isc/buffer.h b/lib/isc/include/isc/buffer.h index e55c5b0..30a6e39 100644 --- a/lib/isc/include/isc/buffer.h +++ b/lib/isc/include/isc/buffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: buffer.h,v 1.53 2008-09-25 04:02:39 tbox Exp $ */ +/* $Id: buffer.h,v 1.55 2010-12-20 23:47:21 tbox Exp $ */ #ifndef ISC_BUFFER_H #define ISC_BUFFER_H 1 diff --git a/lib/isc/include/isc/entropy.h b/lib/isc/include/isc/entropy.h index 1eb8fd1..e115906 100644 --- a/lib/isc/include/isc/entropy.h +++ b/lib/isc/include/isc/entropy.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: entropy.h,v 1.32.332.3 2009-10-19 02:46:07 marka Exp $ */ +/* $Id: entropy.h,v 1.35 2009-10-19 02:37:08 marka Exp $ */ #ifndef ISC_ENTROPY_H #define ISC_ENTROPY_H 1 diff --git a/lib/isc/include/isc/error.h b/lib/isc/include/isc/error.h index a0025e0..d3dcc8b 100644 --- a/lib/isc/include/isc/error.h +++ b/lib/isc/include/isc/error.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: error.h,v 1.20 2007-06-19 23:47:18 tbox Exp $ */ +/* $Id: error.h,v 1.22 2009-09-29 23:48:04 tbox Exp $ */ #ifndef ISC_ERROR_H #define ISC_ERROR_H 1 @@ -26,6 +26,7 @@ #include #include +#include ISC_LANG_BEGINDECLS @@ -45,9 +46,9 @@ isc_error_unexpected(const char *, int, const char *, ...) ISC_FORMAT_PRINTF(3, 4); /*% fatal error */ -void +ISC_PLATFORM_NORETURN_PRE void isc_error_fatal(const char *, int, const char *, ...) - ISC_FORMAT_PRINTF(3, 4); +ISC_FORMAT_PRINTF(3, 4) ISC_PLATFORM_NORETURN_POST; /*% runtimecheck error */ void diff --git a/lib/isc/include/isc/file.h b/lib/isc/include/isc/file.h index 6629a3e..be40825 100644 --- a/lib/isc/include/isc/file.h +++ b/lib/isc/include/isc/file.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: file.h,v 1.33.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: file.h,v 1.39 2011-01-11 23:47:14 tbox Exp $ */ #ifndef ISC_FILE_H #define ISC_FILE_H 1 @@ -100,6 +100,10 @@ isc_file_mktemplate(const char *path, char *buf, size_t buflen); isc_result_t isc_file_openunique(char *templet, FILE **fp); +isc_result_t +isc_file_openuniqueprivate(char *templet, FILE **fp); +isc_result_t +isc_file_openuniquemode(char *templet, int mode, FILE **fp); /*!< * \brief Create and open a file with a unique name based on 'templet'. * @@ -251,6 +255,29 @@ isc_file_truncate(const char *filename, isc_offset_t size); * Truncate/extend the file specified to 'size' bytes. */ +isc_result_t +isc_file_safecreate(const char *filename, FILE **fp); +/*%< + * Open 'filename' for writing, truncating if necessary. Ensure that + * if it existed it was a normal file. If creating the file, ensure + * that only the owner can read/write it. + */ + +isc_result_t +isc_file_splitpath(isc_mem_t *mctx, char *path, + char **dirname, char **basename); +/*%< + * Split a path into dirname and basename. If 'path' contains no slash + * (or, on windows, backslash), then '*dirname' is set to ".". + * + * Allocates memory for '*dirname', which can be freed with isc_mem_free(). + * + * Returns: + * - ISC_R_SUCCESS on success + * - ISC_R_INVALIDFILE if 'path' is empty or ends with '/' + * - ISC_R_NOMEMORY if unable to allocate memory + */ + ISC_LANG_ENDDECLS #endif /* ISC_FILE_H */ diff --git a/lib/isc/include/isc/fsaccess.h b/lib/isc/include/isc/fsaccess.h index 88469dd..9758242 100644 --- a/lib/isc/include/isc/fsaccess.h +++ b/lib/isc/include/isc/fsaccess.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: fsaccess.h,v 1.14.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: fsaccess.h,v 1.16 2009-01-17 23:47:43 tbox Exp $ */ #ifndef ISC_FSACCESS_H #define ISC_FSACCESS_H 1 diff --git a/lib/isc/include/isc/hash.h b/lib/isc/include/isc/hash.h index 9bfb709..543e5fd 100644 --- a/lib/isc/include/isc/hash.h +++ b/lib/isc/include/isc/hash.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: hash.h,v 1.10.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: hash.h,v 1.12 2009-01-17 23:47:43 tbox Exp $ */ #ifndef ISC_HASH_H #define ISC_HASH_H 1 diff --git a/lib/isc/include/isc/heap.h b/lib/isc/include/isc/heap.h index ae346c1..943ace3 100644 --- a/lib/isc/include/isc/heap.h +++ b/lib/isc/include/isc/heap.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: heap.h,v 1.24.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: heap.h,v 1.26 2009-01-17 23:47:43 tbox Exp $ */ #ifndef ISC_HEAP_H #define ISC_HEAP_H 1 diff --git a/lib/isc/include/isc/hmacmd5.h b/lib/isc/include/isc/hmacmd5.h index 68074ae..c7d7fff 100644 --- a/lib/isc/include/isc/hmacmd5.h +++ b/lib/isc/include/isc/hmacmd5.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: hmacmd5.h,v 1.12 2007-06-19 23:47:18 tbox Exp $ */ +/* $Id: hmacmd5.h,v 1.14 2009-02-06 23:47:42 tbox Exp $ */ /*! \file isc/hmacmd5.h * \brief This is the header file for the HMAC-MD5 keyed hash algorithm @@ -27,14 +27,23 @@ #include #include +#include #include #define ISC_HMACMD5_KEYLENGTH 64 +#ifdef ISC_PLATFORM_OPENSSLHASH +#include + +typedef HMAC_CTX isc_hmacmd5_t; + +#else + typedef struct { isc_md5_t md5ctx; unsigned char key[ISC_HMACMD5_KEYLENGTH]; } isc_hmacmd5_t; +#endif ISC_LANG_BEGINDECLS diff --git a/lib/isc/include/isc/hmacsha.h b/lib/isc/include/isc/hmacsha.h index c439883..286cafc 100644 --- a/lib/isc/include/isc/hmacsha.h +++ b/lib/isc/include/isc/hmacsha.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2005-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: hmacsha.h,v 1.7 2007-06-19 23:47:18 tbox Exp $ */ +/* $Id: hmacsha.h,v 1.9 2009-02-06 23:47:42 tbox Exp $ */ /*! \file isc/hmacsha.h * This is the header file for the HMAC-SHA1, HMAC-SHA224, HMAC-SHA256, @@ -25,6 +25,7 @@ #define ISC_HMACSHA_H 1 #include +#include #include #include #include @@ -35,6 +36,17 @@ #define ISC_HMACSHA384_KEYLENGTH ISC_SHA384_BLOCK_LENGTH #define ISC_HMACSHA512_KEYLENGTH ISC_SHA512_BLOCK_LENGTH +#ifdef ISC_PLATFORM_OPENSSLHASH +#include + +typedef HMAC_CTX isc_hmacsha1_t; +typedef HMAC_CTX isc_hmacsha224_t; +typedef HMAC_CTX isc_hmacsha256_t; +typedef HMAC_CTX isc_hmacsha384_t; +typedef HMAC_CTX isc_hmacsha512_t; + +#else + typedef struct { isc_sha1_t sha1ctx; unsigned char key[ISC_HMACSHA1_KEYLENGTH]; @@ -59,6 +71,7 @@ typedef struct { isc_sha512_t sha512ctx; unsigned char key[ISC_HMACSHA512_KEYLENGTH]; } isc_hmacsha512_t; +#endif ISC_LANG_BEGINDECLS diff --git a/lib/isc/include/isc/lib.h b/lib/isc/include/isc/lib.h index 3804a07..c8bdbc6 100644 --- a/lib/isc/include/isc/lib.h +++ b/lib/isc/include/isc/lib.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lib.h,v 1.14 2007-06-19 23:47:18 tbox Exp $ */ +/* $Id: lib.h,v 1.16 2009-09-02 23:48:03 tbox Exp $ */ #ifndef ISC_LIB_H #define ISC_LIB_H 1 @@ -36,6 +36,15 @@ isc_lib_initmsgcat(void); * has not already been initialized. */ +void +isc_lib_register(void); +/*!< + * \brief Register the ISC library implementations for some base services + * such as memory or event management and handling socket or timer events. + * An external application that wants to use the ISC library must call this + * function very early in main(). + */ + ISC_LANG_ENDDECLS #endif /* ISC_LIB_H */ diff --git a/lib/isc/include/isc/log.h b/lib/isc/include/isc/log.h index fec3d9d..eac5755 100644 --- a/lib/isc/include/isc/log.h +++ b/lib/isc/include/isc/log.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: log.h,v 1.54.332.5 2009-02-16 02:04:05 marka Exp $ */ +/* $Id: log.h,v 1.59 2009-02-16 02:01:16 marka Exp $ */ #ifndef ISC_LOG_H #define ISC_LOG_H 1 diff --git a/lib/isc/include/isc/md5.h b/lib/isc/include/isc/md5.h index 9d5b1ec..9017115 100644 --- a/lib/isc/include/isc/md5.h +++ b/lib/isc/include/isc/md5.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: md5.h,v 1.16 2007-06-19 23:47:18 tbox Exp $ */ +/* $Id: md5.h,v 1.20 2010-01-07 23:48:54 tbox Exp $ */ /*! \file isc/md5.h * \brief This is the header file for the MD5 message-digest algorithm. @@ -44,15 +44,25 @@ #define ISC_MD5_H 1 #include +#include #include #define ISC_MD5_DIGESTLENGTH 16U +#define ISC_MD5_BLOCK_LENGTH 64U + +#ifdef ISC_PLATFORM_OPENSSLHASH +#include + +typedef EVP_MD_CTX isc_md5_t; + +#else typedef struct { isc_uint32_t buf[4]; isc_uint32_t bytes[2]; isc_uint32_t in[16]; } isc_md5_t; +#endif ISC_LANG_BEGINDECLS diff --git a/lib/isc/include/isc/mem.h b/lib/isc/include/isc/mem.h index d13d912..e0a7fe5 100644 --- a/lib/isc/include/isc/mem.h +++ b/lib/isc/include/isc/mem.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mem.h,v 1.78.120.6 2010-08-11 23:04:21 jinmei Exp $ */ +/* $Id: mem.h,v 1.89 2010-08-11 22:54:58 jinmei Exp $ */ #ifndef ISC_MEM_H #define ISC_MEM_H 1 @@ -152,11 +152,29 @@ LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_debugging; #endif -#define isc_mem_get(c, s) isc__mem_get((c), (s) _ISC_MEM_FILELINE) -#define isc_mem_allocate(c, s) isc__mem_allocate((c), (s) _ISC_MEM_FILELINE) -#define isc_mem_reallocate(c, p, s) isc__mem_reallocate((c), (p), (s) _ISC_MEM_FILELINE) -#define isc_mem_strdup(c, p) isc__mem_strdup((c), (p) _ISC_MEM_FILELINE) -#define isc_mempool_get(c) isc__mempool_get((c) _ISC_MEM_FILELINE) +/*%< + * We use either isc___mem (three underscores) or isc__mem (two) depending on + * whether it's for BIND9's internal purpose (with -DBIND9) or generic export + * library. This condition is generally handled in isc/namespace.h, but for + * Windows it doesn't work if it involves multiple times of macro expansion + * (such as isc_mem to isc__mem then to isc___mem). The following definitions + * are used to work around this portability issue. Right now, we don't support + * the export library for Windows, so we always use the three-underscore + * version. + */ +#ifdef WIN32 +#define ISCMEMFUNC(sfx) isc___mem_ ## sfx +#define ISCMEMPOOLFUNC(sfx) isc___mempool_ ## sfx +#else +#define ISCMEMFUNC(sfx) isc__mem_ ## sfx +#define ISCMEMPOOLFUNC(sfx) isc__mempool_ ## sfx +#endif + +#define isc_mem_get(c, s) ISCMEMFUNC(get)((c), (s) _ISC_MEM_FILELINE) +#define isc_mem_allocate(c, s) ISCMEMFUNC(allocate)((c), (s) _ISC_MEM_FILELINE) +#define isc_mem_reallocate(c, p, s) ISCMEMFUNC(reallocate)((c), (p), (s) _ISC_MEM_FILELINE) +#define isc_mem_strdup(c, p) ISCMEMFUNC(strdup)((c), (p) _ISC_MEM_FILELINE) +#define isc_mempool_get(c) ISCMEMPOOLFUNC(get)((c) _ISC_MEM_FILELINE) /*% * isc_mem_putanddetach() is a convenience function for use where you @@ -187,33 +205,102 @@ LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_debugging; * \endcode */ +/*% memory and memory pool methods */ +typedef struct isc_memmethods { + void (*attach)(isc_mem_t *source, isc_mem_t **targetp); + void (*detach)(isc_mem_t **mctxp); + void (*destroy)(isc_mem_t **mctxp); + void *(*memget)(isc_mem_t *mctx, size_t size _ISC_MEM_FLARG); + void (*memput)(isc_mem_t *mctx, void *ptr, size_t size _ISC_MEM_FLARG); + void (*memputanddetach)(isc_mem_t **mctxp, void *ptr, + size_t size _ISC_MEM_FLARG); + void *(*memallocate)(isc_mem_t *mctx, size_t size _ISC_MEM_FLARG); + void *(*memreallocate)(isc_mem_t *mctx, void *ptr, + size_t size _ISC_MEM_FLARG); + char *(*memstrdup)(isc_mem_t *mctx, const char *s _ISC_MEM_FLARG); + void (*memfree)(isc_mem_t *mctx, void *ptr _ISC_MEM_FLARG); + void (*setdestroycheck)(isc_mem_t *mctx, isc_boolean_t flag); + void (*setwater)(isc_mem_t *ctx, isc_mem_water_t water, + void *water_arg, size_t hiwater, size_t lowater); + void (*waterack)(isc_mem_t *ctx, int flag); + size_t (*inuse)(isc_mem_t *mctx); + isc_boolean_t (*isovermem)(isc_mem_t *mctx); + isc_result_t (*mpcreate)(isc_mem_t *mctx, size_t size, + isc_mempool_t **mpctxp); +} isc_memmethods_t; + +typedef struct isc_mempoolmethods { + void (*destroy)(isc_mempool_t **mpctxp); + void *(*get)(isc_mempool_t *mpctx _ISC_MEM_FLARG); + void (*put)(isc_mempool_t *mpctx, void *mem _ISC_MEM_FLARG); + unsigned int (*getallocated)(isc_mempool_t *mpctx); + void (*setmaxalloc)(isc_mempool_t *mpctx, unsigned int limit); + void (*setfreemax)(isc_mempool_t *mpctx, unsigned int limit); + void (*setname)(isc_mempool_t *mpctx, const char *name); + void (*associatelock)(isc_mempool_t *mpctx, isc_mutex_t *lock); + void (*setfillcount)(isc_mempool_t *mpctx, unsigned int limit); +} isc_mempoolmethods_t; + +/*% + * This structure is actually just the common prefix of a memory context + * implementation's version of an isc_mem_t. + * \brief + * Direct use of this structure by clients is forbidden. mctx implementations + * may change the structure. 'magic' must be ISCAPI_MCTX_MAGIC for any of the + * isc_mem_ routines to work. mctx implementations must maintain all mctx + * invariants. + */ +struct isc_mem { + unsigned int impmagic; + unsigned int magic; + isc_memmethods_t *methods; +}; + +#define ISCAPI_MCTX_MAGIC ISC_MAGIC('A','m','c','x') +#define ISCAPI_MCTX_VALID(m) ((m) != NULL && \ + (m)->magic == ISCAPI_MCTX_MAGIC) + +/*% + * This is the common prefix of a memory pool context. The same note as + * that for the mem structure applies. + */ +struct isc_mempool { + unsigned int impmagic; + unsigned int magic; + isc_mempoolmethods_t *methods; +}; + +#define ISCAPI_MPOOL_MAGIC ISC_MAGIC('A','m','p','l') +#define ISCAPI_MPOOL_VALID(mp) ((mp) != NULL && \ + (mp)->magic == ISCAPI_MPOOL_MAGIC) + #if ISC_MEM_DEBUG #define isc_mem_put(c, p, s) \ do { \ - isc__mem_put((c), (p), (s) _ISC_MEM_FILELINE); \ + ISCMEMFUNC(put)((c), (p), (s) _ISC_MEM_FILELINE); \ (p) = NULL; \ } while (0) #define isc_mem_putanddetach(c, p, s) \ do { \ - isc__mem_putanddetach((c), (p), (s) _ISC_MEM_FILELINE); \ + ISCMEMFUNC(putanddetach)((c), (p), (s) _ISC_MEM_FILELINE); \ (p) = NULL; \ } while (0) #define isc_mem_free(c, p) \ do { \ - isc__mem_free((c), (p) _ISC_MEM_FILELINE); \ + ISCMEMFUNC(free)((c), (p) _ISC_MEM_FILELINE); \ (p) = NULL; \ } while (0) #define isc_mempool_put(c, p) \ do { \ - isc__mempool_put((c), (p) _ISC_MEM_FILELINE); \ + ISCMEMPOOLFUNC(put)((c), (p) _ISC_MEM_FILELINE); \ (p) = NULL; \ } while (0) #else -#define isc_mem_put(c, p, s) isc__mem_put((c), (p), (s) _ISC_MEM_FILELINE) +#define isc_mem_put(c, p, s) ISCMEMFUNC(put)((c), (p), (s) _ISC_MEM_FILELINE) #define isc_mem_putanddetach(c, p, s) \ - isc__mem_putanddetach((c), (p), (s) _ISC_MEM_FILELINE) -#define isc_mem_free(c, p) isc__mem_free((c), (p) _ISC_MEM_FILELINE) -#define isc_mempool_put(c, p) isc__mempool_put((c), (p) _ISC_MEM_FILELINE) + ISCMEMFUNC(putanddetach)((c), (p), (s) _ISC_MEM_FILELINE) +#define isc_mem_free(c, p) ISCMEMFUNC(free)((c), (p) _ISC_MEM_FILELINE) +#define isc_mempool_put(c, p) ISCMEMPOOLFUNC(put)((c), (p) _ISC_MEM_FILELINE) #endif /*@{*/ @@ -613,24 +700,50 @@ isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit); * Pseudo-private functions for use via macros. Do not call directly. */ void * -isc__mem_get(isc_mem_t *, size_t _ISC_MEM_FLARG); +ISCMEMFUNC(get)(isc_mem_t *, size_t _ISC_MEM_FLARG); void -isc__mem_putanddetach(isc_mem_t **, void *, - size_t _ISC_MEM_FLARG); +ISCMEMFUNC(putanddetach)(isc_mem_t **, void *, size_t _ISC_MEM_FLARG); void -isc__mem_put(isc_mem_t *, void *, size_t _ISC_MEM_FLARG); +ISCMEMFUNC(put)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG); void * -isc__mem_allocate(isc_mem_t *, size_t _ISC_MEM_FLARG); +ISCMEMFUNC(allocate)(isc_mem_t *, size_t _ISC_MEM_FLARG); void * -isc__mem_reallocate(isc_mem_t *, void *, size_t _ISC_MEM_FLARG); +ISCMEMFUNC(reallocate)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG); void -isc__mem_free(isc_mem_t *, void * _ISC_MEM_FLARG); +ISCMEMFUNC(free)(isc_mem_t *, void * _ISC_MEM_FLARG); char * -isc__mem_strdup(isc_mem_t *, const char *_ISC_MEM_FLARG); +ISCMEMFUNC(strdup)(isc_mem_t *, const char *_ISC_MEM_FLARG); void * -isc__mempool_get(isc_mempool_t * _ISC_MEM_FLARG); +ISCMEMPOOLFUNC(get)(isc_mempool_t * _ISC_MEM_FLARG); void -isc__mempool_put(isc_mempool_t *, void * _ISC_MEM_FLARG); +ISCMEMPOOLFUNC(put)(isc_mempool_t *, void * _ISC_MEM_FLARG); + +#ifdef USE_MEMIMPREGISTER + +/*%< + * See isc_mem_create2() above. + */ +typedef isc_result_t +(*isc_memcreatefunc_t)(size_t init_max_size, size_t target_size, + isc_mem_t **ctxp, unsigned int flags); + +isc_result_t +isc_mem_register(isc_memcreatefunc_t createfunc); +/*%< + * Register a new memory management implementation and add it to the list of + * supported implementations. This function must be called when a different + * memory management library is used than the one contained in the ISC library. + */ + +isc_result_t +isc__mem_register(void); +/*%< + * A short cut function that specifies the memory management module in the ISC + * library for isc_mem_register(). An application that uses the ISC library + * usually do not have to care about this function: it would call + * isc_lib_register(), which internally calls this function. + */ +#endif /* USE_MEMIMPREGISTER */ ISC_LANG_ENDDECLS diff --git a/lib/isc/include/isc/msgs.h b/lib/isc/include/isc/msgs.h index 674371f5..22dfde2 100644 --- a/lib/isc/include/isc/msgs.h +++ b/lib/isc/include/isc/msgs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: msgs.h,v 1.17 2008-08-08 06:28:59 tbox Exp $ */ +/* $Id: msgs.h,v 1.19 2009-10-01 23:48:08 tbox Exp $ */ #ifndef ISC_MSGS_H #define ISC_MSGS_H 1 @@ -156,7 +156,7 @@ #define ISC_MSG_FILTER 1421 /*%< setsockopt(SO_ACCEPTFILTER): %s */ #define ISC_MSG_TOOMANYHANDLES 1422 /*%< %s: too many open WSA event handles: %s */ - +#define ISC_MSG_POKED 1423 /*%< "poked flags: %d" */ #define ISC_MSG_AWAKE 1502 /*%< "awake" */ #define ISC_MSG_WORKING 1503 /*%< "working" */ diff --git a/lib/isc/include/isc/namespace.h b/lib/isc/include/isc/namespace.h new file mode 100644 index 0000000..05a8b2c --- /dev/null +++ b/lib/isc/include/isc/namespace.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: namespace.h,v 1.9 2010-12-04 13:25:59 marka Exp $ */ + +#ifndef ISCAPI_NAMESPACE_H +#define ISCAPI_NAMESPACE_H 1 + +/*% + * name space conversions + */ + +#ifdef BIND9 + +#define isc_app_start isc__app_start +#define isc_app_ctxstart isc__app_ctxstart +#define isc_app_onrun isc__app_onrun +#define isc_app_run isc__app_run +#define isc_app_ctxrun isc__app_ctxrun +#define isc_app_shutdown isc__app_shutdown +#define isc_app_ctxshutdown isc__app_ctxshutdown +#define isc_app_ctxsuspend isc__app_ctxsuspend +#define isc_app_reload isc__app_reload +#define isc_app_finish isc__app_finish +#define isc_app_block isc__app_block +#define isc_app_unblock isc__app_unblock +#define isc_appctx_create isc__appctx_create +#define isc_appctx_destroy isc__appctx_destroy +#define isc_appctx_settaskmgr isc__appctx_settaskmgr +#define isc_appctx_setsocketmgr isc__appctx_setsocketmgr +#define isc_appctx_settimermgr isc__appctx_settimermgr + +#define isc_mem_checkdestroyed isc__mem_checkdestroyed +#define isc_mem_createx isc__mem_createx +#define isc_mem_createx2 isc__mem_createx2 +#define isc_mem_create isc__mem_create +#define isc_mem_create2 isc__mem_create2 +#define isc_mem_attach isc__mem_attach +#define isc_mem_detach isc__mem_detach +#define isc__mem_putanddetach isc___mem_putanddetach +#define isc_mem_destroy isc__mem_destroy +#define isc_mem_ondestroy isc__mem_ondestroy +#define isc__mem_get isc___mem_get +#define isc__mem_put isc___mem_put +#define isc_mem_stats isc__mem_stats +#define isc__mem_allocate isc___mem_allocate +#define isc__mem_free isc___mem_free +#define isc__mem_strdup isc___mem_strdup +#define isc__mem_reallocate isc___mem_reallocate +#define isc_mem_references isc__mem_references +#define isc_mem_setdestroycheck isc__mem_setdestroycheck +#define isc_mem_setquota isc__mem_setquota +#define isc_mem_getname isc__mem_getname +#define isc_mem_getquota isc__mem_getquota +#define isc_mem_gettag isc__mem_gettag +#define isc_mem_inuse isc__mem_inuse +#define isc_mem_isovermem isc__mem_isovermem +#define isc_mem_setname isc__mem_setname +#define isc_mem_setwater isc__mem_setwater +#define isc_mem_printallactive isc__mem_printallactive +#define isc_mem_waterack isc__mem_waterack +#define isc_mempool_create isc__mempool_create +#define isc_mempool_setname isc__mempool_setname +#define isc_mempool_destroy isc__mempool_destroy +#define isc_mempool_associatelock isc__mempool_associatelock +#define isc__mempool_get isc___mempool_get +#define isc__mempool_put isc___mempool_put +#define isc_mempool_setfreemax isc__mempool_setfreemax +#define isc_mempool_getfreemax isc__mempool_getfreemax +#define isc_mempool_getfreecount isc__mempool_getfreecount +#define isc_mempool_setmaxalloc isc__mempool_setmaxalloc +#define isc_mempool_getmaxalloc isc__mempool_getmaxalloc +#define isc_mempool_getallocated isc__mempool_getallocated +#define isc_mempool_setfillcount isc__mempool_setfillcount +#define isc_mempool_getfillcount isc__mempool_getfillcount + +#define isc_socket_create isc__socket_create +#define isc_socket_attach isc__socket_attach +#define isc_socket_detach isc__socket_detach +#define isc_socketmgr_create isc__socketmgr_create +#define isc_socketmgr_create2 isc__socketmgr_create2 +#define isc_socketmgr_destroy isc__socketmgr_destroy +#define isc_socket_open isc__socket_open +#define isc_socket_close isc__socket_close +#define isc_socket_recvv isc__socket_recvv +#define isc_socket_recv isc__socket_recv +#define isc_socket_recv2 isc__socket_recv2 +#define isc_socket_send isc__socket_send +#define isc_socket_sendto isc__socket_sendto +#define isc_socket_sendv isc__socket_sendv +#define isc_socket_sendtov isc__socket_sendtov +#define isc_socket_sendto2 isc__socket_sendto2 +#define isc_socket_cleanunix isc__socket_cleanunix +#define isc_socket_permunix isc__socket_permunix +#define isc_socket_bind isc__socket_bind +#define isc_socket_filter isc__socket_filter +#define isc_socket_listen isc__socket_listen +#define isc_socket_accept isc__socket_accept +#define isc_socket_connect isc__socket_connect +#define isc_socket_getname isc__socket_getname +#define isc_socket_gettag isc__socket_gettag +#define isc_socket_getpeername isc__socket_getpeername +#define isc_socket_getsockname isc__socket_getsockname +#define isc_socket_cancel isc__socket_cancel +#define isc_socket_gettype isc__socket_gettype +#define isc_socket_isbound isc__socket_isbound +#define isc_socket_ipv6only isc__socket_ipv6only +#define isc_socket_setname isc__socket_setname +#define isc_socketmgr_getmaxsockets isc__socketmgr_getmaxsockets +#define isc_socketmgr_setstats isc__socketmgr_setstats +#define isc_socketmgr_setreserved isc__socketmgr_setreserved +#define isc__socketmgr_maxudp isc___socketmgr_maxudp +#define isc_socket_fdwatchcreate isc__socket_fdwatchcreate +#define isc_socket_fdwatchpoke isc__socket_fdwatchpoke + +#define isc_task_create isc__task_create +#define isc_task_attach isc__task_attach +#define isc_task_detach isc__task_detach +/* #define isc_task_exiting isc__task_exiting XXXMPA */ +#define isc_task_send isc__task_send +#define isc_task_sendanddetach isc__task_sendanddetach +#define isc_task_purgerange isc__task_purgerange +#define isc_task_purge isc__task_purge +#define isc_task_purgeevent isc__task_purgeevent +#define isc_task_unsendrange isc__task_unsendrange +#define isc_task_unsend isc__task_unsend +#define isc_task_onshutdown isc__task_onshutdown +#define isc_task_shutdown isc__task_shutdown +#define isc_task_destroy isc__task_destroy +#define isc_task_setname isc__task_setname +#define isc_task_getname isc__task_getname +#define isc_task_gettag isc__task_gettag +#define isc_task_getcurrenttime isc__task_getcurrenttime +#define isc_taskmgr_create isc__taskmgr_create +#define isc_taskmgr_destroy isc__taskmgr_destroy +#define isc_task_beginexclusive isc__task_beginexclusive +#define isc_task_endexclusive isc__task_endexclusive + +#define isc_timer_create isc__timer_create +#define isc_timer_reset isc__timer_reset +#define isc_timer_gettype isc__timer_gettype +#define isc_timer_touch isc__timer_touch +#define isc_timer_attach isc__timer_attach +#define isc_timer_detach isc__timer_detach +#define isc_timermgr_create isc__timermgr_create +#define isc_timermgr_poke isc__timermgr_poke +#define isc_timermgr_destroy isc__timermgr_destroy + +#endif /* BIND9 */ + +#endif /* ISCAPI_NAMESPACE_H */ diff --git a/lib/isc/include/isc/netaddr.h b/lib/isc/include/isc/netaddr.h index 52418ec..04b7ec1 100644 --- a/lib/isc/include/isc/netaddr.h +++ b/lib/isc/include/isc/netaddr.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: netaddr.h,v 1.35.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: netaddr.h,v 1.37 2009-01-17 23:47:43 tbox Exp $ */ #ifndef ISC_NETADDR_H #define ISC_NETADDR_H 1 diff --git a/lib/isc/include/isc/netscope.h b/lib/isc/include/isc/netscope.h index 7b2c13c..1a50816 100644 --- a/lib/isc/include/isc/netscope.h +++ b/lib/isc/include/isc/netscope.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: netscope.h,v 1.11.332.2 2009-06-25 23:47:24 tbox Exp $ */ +/* $Id: netscope.h,v 1.13 2009-06-25 23:48:02 tbox Exp $ */ #ifndef ISC_NETSCOPE_H #define ISC_NETSCOPE_H 1 diff --git a/lib/isc/include/isc/platform.h.in b/lib/isc/include/isc/platform.h.in index 99c887b..2491274 100644 --- a/lib/isc/include/isc/platform.h.in +++ b/lib/isc/include/isc/platform.h.in @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: platform.h.in,v 1.48.84.4 2010-06-03 23:47:49 tbox Exp $ */ +/* $Id: platform.h.in,v 1.56 2010-12-18 01:56:23 each Exp $ */ #ifndef ISC_PLATFORM_H #define ISC_PLATFORM_H 1 @@ -146,6 +146,11 @@ */ @ISC_PLATFORM_HAVEDEVPOLL@ +/*! \brief + * Define if we want to log backtrace + */ +@ISC_PLATFORM_USEBACKTRACE@ + /* *** Printing. ***/ @@ -215,6 +220,12 @@ @ISC_PLATFORM_GSSAPIHEADER@ /* + * Defined to or for how to + * include the GSSAPI KRB5 header. + */ +@ISC_PLATFORM_GSSAPI_KRB5_HEADER@ + +/* * Defined to or for how to include * the KRB5 header. */ @@ -290,6 +301,17 @@ */ @ISC_PLATFORM_HAVESTRINGSH@ +/* + * Define if the hash functions must be provided by OpenSSL. + */ +@ISC_PLATFORM_OPENSSLHASH@ + +/* + * Defines for the noreturn attribute. + */ +@ISC_PLATFORM_NORETURN_PRE@ +@ISC_PLATFORM_NORETURN_POST@ + /*** *** Windows dll support. ***/ diff --git a/lib/isc/include/isc/portset.h b/lib/isc/include/isc/portset.h index a257322..2e27467 100644 --- a/lib/isc/include/isc/portset.h +++ b/lib/isc/include/isc/portset.h @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: portset.h,v 1.3.90.3 2009-06-25 05:31:51 marka Exp $ */ +/* $Id: portset.h,v 1.6 2009-06-25 05:28:34 marka Exp $ */ /*! \file isc/portset.h * \brief Transport Protocol Port Manipulation Module diff --git a/lib/isc/include/isc/radix.h b/lib/isc/include/isc/radix.h index fa5e294..ed8aaf2 100644 --- a/lib/isc/include/isc/radix.h +++ b/lib/isc/include/isc/radix.h @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: radix.h,v 1.11.44.2 2008-12-24 23:47:02 tbox Exp $ */ +/* $Id: radix.h,v 1.13 2008-12-01 23:47:45 tbox Exp $ */ /* * This source was adapted from MRT's RCS Ids: diff --git a/lib/isc/include/isc/random.h b/lib/isc/include/isc/random.h index 9743cb4..e05b204 100644 --- a/lib/isc/include/isc/random.h +++ b/lib/isc/include/isc/random.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: random.h,v 1.18.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: random.h,v 1.20 2009-01-17 23:47:43 tbox Exp $ */ #ifndef ISC_RANDOM_H #define ISC_RANDOM_H 1 diff --git a/lib/isc/include/isc/ratelimiter.h b/lib/isc/include/isc/ratelimiter.h index 7ed312a..f8a9819 100644 --- a/lib/isc/include/isc/ratelimiter.h +++ b/lib/isc/include/isc/ratelimiter.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ratelimiter.h,v 1.21.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: ratelimiter.h,v 1.23 2009-01-18 23:48:14 tbox Exp $ */ #ifndef ISC_RATELIMITER_H #define ISC_RATELIMITER_H 1 diff --git a/lib/isc/include/isc/refcount.h b/lib/isc/include/isc/refcount.h index 8e83a13..71f35f1 100644 --- a/lib/isc/include/isc/refcount.h +++ b/lib/isc/include/isc/refcount.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: refcount.h,v 1.15 2007-06-19 23:47:18 tbox Exp $ */ +/* $Id: refcount.h,v 1.17 2009-09-29 23:48:04 tbox Exp $ */ #ifndef ISC_REFCOUNT_H #define ISC_REFCOUNT_H 1 @@ -28,7 +28,7 @@ #include /*! \file isc/refcount.h - * \brief Implements a locked reference counter. + * \brief Implements a locked reference counter. * * These functions may actually be * implemented using macros, and implementations of these macros are below. @@ -42,7 +42,7 @@ ISC_LANG_BEGINDECLS * Function prototypes */ -/* +/* * isc_result_t * isc_refcount_init(isc_refcount_t *ref, unsigned int n); * @@ -103,7 +103,7 @@ typedef struct isc_refcount { isc_int32_t refs; } isc_refcount_t; -#define isc_refcount_destroy(rp) (REQUIRE((rp)->refs == 0)) +#define isc_refcount_destroy(rp) REQUIRE((rp)->refs == 0) #define isc_refcount_current(rp) ((unsigned int)((rp)->refs)) #define isc_refcount_increment0(rp, tp) \ @@ -192,7 +192,7 @@ typedef struct isc_refcount { int refs; } isc_refcount_t; -#define isc_refcount_destroy(rp) (REQUIRE((rp)->refs == 0)) +#define isc_refcount_destroy(rp) REQUIRE((rp)->refs == 0) #define isc_refcount_current(rp) ((unsigned int)((rp)->refs)) #define isc_refcount_increment0(rp, tp) \ diff --git a/lib/isc/include/isc/result.h b/lib/isc/include/isc/result.h index 804ab5e..cc591dc 100644 --- a/lib/isc/include/isc/result.h +++ b/lib/isc/include/isc/result.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: result.h,v 1.71 2008-09-25 04:02:39 tbox Exp $ */ +/* $Id: result.h,v 1.73 2009-09-02 23:48:03 tbox Exp $ */ #ifndef ISC_RESULT_H #define ISC_RESULT_H 1 @@ -42,6 +42,7 @@ #define ISC_R_EOF 14 /*%< end of file */ #define ISC_R_BOUND 15 /*%< socket already bound */ #define ISC_R_RELOAD 16 /*%< reload */ +#define ISC_R_SUSPEND ISC_R_RELOAD /*%< alias of 'reload' */ #define ISC_R_LOCKBUSY 17 /*%< lock busy */ #define ISC_R_EXISTS 18 /*%< already exists */ #define ISC_R_NOSPACE 19 /*%< ran out of space */ diff --git a/lib/isc/include/isc/resultclass.h b/lib/isc/include/isc/resultclass.h index 86c55b6..84f6c64 100644 --- a/lib/isc/include/isc/resultclass.h +++ b/lib/isc/include/isc/resultclass.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resultclass.h,v 1.18 2007-06-19 23:47:18 tbox Exp $ */ +/* $Id: resultclass.h,v 1.20 2009-09-02 23:48:03 tbox Exp $ */ #ifndef ISC_RESULTCLASS_H #define ISC_RESULTCLASS_H 1 @@ -45,6 +45,7 @@ #define ISC_RESULTCLASS_DNSRCODE ISC_RESULTCLASS_FROMNUM(3) #define ISC_RESULTCLASS_OMAPI ISC_RESULTCLASS_FROMNUM(4) #define ISC_RESULTCLASS_ISCCC ISC_RESULTCLASS_FROMNUM(5) +#define ISC_RESULTCLASS_DHCP ISC_RESULTCLASS_FROMNUM(6) #endif /* ISC_RESULTCLASS_H */ diff --git a/lib/isc/include/isc/serial.h b/lib/isc/include/isc/serial.h index 97d5fe1..332709d 100644 --- a/lib/isc/include/isc/serial.h +++ b/lib/isc/include/isc/serial.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: serial.h,v 1.16.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: serial.h,v 1.18 2009-01-18 23:48:14 tbox Exp $ */ #ifndef ISC_SERIAL_H #define ISC_SERIAL_H 1 diff --git a/lib/isc/include/isc/sha1.h b/lib/isc/include/isc/sha1.h index 4da682a..a9d08b9 100644 --- a/lib/isc/include/isc/sha1.h +++ b/lib/isc/include/isc/sha1.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -18,7 +18,7 @@ #ifndef ISC_SHA1_H #define ISC_SHA1_H 1 -/* $Id: sha1.h,v 1.17 2007-06-19 23:47:18 tbox Exp $ */ +/* $Id: sha1.h,v 1.19 2009-02-06 23:47:42 tbox Exp $ */ /* $NetBSD: sha1.h,v 1.2 1998/05/29 22:55:44 thorpej Exp $ */ @@ -29,16 +29,25 @@ */ #include +#include #include #define ISC_SHA1_DIGESTLENGTH 20U #define ISC_SHA1_BLOCK_LENGTH 64U +#ifdef ISC_PLATFORM_OPENSSLHASH +#include + +typedef EVP_MD_CTX isc_sha1_t; + +#else + typedef struct { isc_uint32_t state[5]; isc_uint32_t count[2]; unsigned char buffer[ISC_SHA1_BLOCK_LENGTH]; } isc_sha1_t; +#endif ISC_LANG_BEGINDECLS diff --git a/lib/isc/include/isc/sha2.h b/lib/isc/include/isc/sha2.h index c3130a8..8d4ffa6 100644 --- a/lib/isc/include/isc/sha2.h +++ b/lib/isc/include/isc/sha2.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2005-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sha2.h,v 1.9.332.2 2010-01-15 23:47:34 tbox Exp $ */ +/* $Id: sha2.h,v 1.12 2009-10-22 02:21:31 each Exp $ */ /* $FreeBSD$ */ /* $KAME: sha2.h,v 1.3 2001/03/12 08:27:48 itojun Exp $ */ @@ -58,6 +58,7 @@ #define ISC_SHA2_H #include +#include #include /*** SHA-224/256/384/512 Various Length Definitions ***********************/ @@ -75,10 +76,15 @@ #define ISC_SHA512_DIGESTLENGTH 64U #define ISC_SHA512_DIGESTSTRINGLENGTH (ISC_SHA512_DIGESTLENGTH * 2 + 1) +/*** SHA-256/384/512 Context Structures *******************************/ -ISC_LANG_BEGINDECLS +#ifdef ISC_PLATFORM_OPENSSLHASH +#include -/*** SHA-256/384/512 Context Structures *******************************/ +typedef EVP_MD_CTX isc_sha256_t; +typedef EVP_MD_CTX isc_sha512_t; + +#else /* * Keep buffer immediately after bitcount to preserve alignment. @@ -97,10 +103,13 @@ typedef struct { isc_uint64_t bitcount[2]; isc_uint8_t buffer[ISC_SHA512_BLOCK_LENGTH]; } isc_sha512_t; +#endif typedef isc_sha256_t isc_sha224_t; typedef isc_sha512_t isc_sha384_t; +ISC_LANG_BEGINDECLS + /*** SHA-224/256/384/512 Function Prototypes ******************************/ void isc_sha224_init (isc_sha224_t *); diff --git a/lib/isc/include/isc/sockaddr.h b/lib/isc/include/isc/sockaddr.h index 758cef7..c83655e 100644 --- a/lib/isc/include/isc/sockaddr.h +++ b/lib/isc/include/isc/sockaddr.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sockaddr.h,v 1.55.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: sockaddr.h,v 1.57 2009-01-18 23:48:14 tbox Exp $ */ #ifndef ISC_SOCKADDR_H #define ISC_SOCKADDR_H 1 diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h index 749ee52..0aa71da 100644 --- a/lib/isc/include/isc/socket.h +++ b/lib/isc/include/isc/socket.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: socket.h,v 1.85.58.3 2009-01-29 22:40:35 jinmei Exp $ */ +/* $Id: socket.h,v 1.94 2009-10-01 01:30:01 sar Exp $ */ #ifndef ISC_SOCKET_H #define ISC_SOCKET_H 1 @@ -260,6 +260,85 @@ typedef enum { #define ISC_SOCKFDWATCH_WRITE 0x00000002 /*%< watch for writable */ /*@}*/ +/*% Socket and socket manager methods */ +typedef struct isc_socketmgrmethods { + void (*destroy)(isc_socketmgr_t **managerp); + isc_result_t (*socketcreate)(isc_socketmgr_t *manager, int pf, + isc_sockettype_t type, + isc_socket_t **socketp); + isc_result_t (*fdwatchcreate)(isc_socketmgr_t *manager, int fd, + int flags, + isc_sockfdwatch_t callback, + void *cbarg, isc_task_t *task, + isc_socket_t **socketp); +} isc_socketmgrmethods_t; + +typedef struct isc_socketmethods { + void (*attach)(isc_socket_t *socket, + isc_socket_t **socketp); + void (*detach)(isc_socket_t **socketp); + isc_result_t (*bind)(isc_socket_t *sock, isc_sockaddr_t *sockaddr, + unsigned int options); + isc_result_t (*sendto)(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, + const void *arg, isc_sockaddr_t *address, + struct in6_pktinfo *pktinfo); + isc_result_t (*connect)(isc_socket_t *sock, isc_sockaddr_t *addr, + isc_task_t *task, isc_taskaction_t action, + const void *arg); + isc_result_t (*recv)(isc_socket_t *sock, isc_region_t *region, + unsigned int minimum, isc_task_t *task, + isc_taskaction_t action, const void *arg); + void (*cancel)(isc_socket_t *sock, isc_task_t *task, + unsigned int how); + isc_result_t (*getsockname)(isc_socket_t *sock, + isc_sockaddr_t *addressp); + isc_sockettype_t (*gettype)(isc_socket_t *sock); + void (*ipv6only)(isc_socket_t *sock, isc_boolean_t yes); + isc_result_t (*fdwatchpoke)(isc_socket_t *sock, int flags); +} isc_socketmethods_t; + +/*% + * This structure is actually just the common prefix of a socket manager + * object implementation's version of an isc_socketmgr_t. + * \brief + * Direct use of this structure by clients is forbidden. socket implementations + * may change the structure. 'magic' must be ISCAPI_SOCKETMGR_MAGIC for any + * of the isc_socket_ routines to work. socket implementations must maintain + * all socket invariants. + * In effect, this definition is used only for non-BIND9 version ("export") + * of the library, and the export version does not work for win32. So, to avoid + * the definition conflict with win32/socket.c, we enable this definition only + * for non-Win32 (i.e. Unix) platforms. + */ +#ifndef WIN32 +struct isc_socketmgr { + unsigned int impmagic; + unsigned int magic; + isc_socketmgrmethods_t *methods; +}; +#endif + +#define ISCAPI_SOCKETMGR_MAGIC ISC_MAGIC('A','s','m','g') +#define ISCAPI_SOCKETMGR_VALID(m) ((m) != NULL && \ + (m)->magic == ISCAPI_SOCKETMGR_MAGIC) + +/*% + * This is the common prefix of a socket object. The same note as + * that for the socketmgr structure applies. + */ +#ifndef WIN32 +struct isc_socket { + unsigned int impmagic; + unsigned int magic; + isc_socketmethods_t *methods; +}; +#endif + +#define ISCAPI_SOCKET_MAGIC ISC_MAGIC('A','s','c','t') +#define ISCAPI_SOCKET_VALID(s) ((s) != NULL && \ + (s)->magic == ISCAPI_SOCKET_MAGIC) + /*** *** Socket and Socket Manager Functions *** @@ -307,6 +386,35 @@ isc_socket_fdwatchcreate(isc_socketmgr_t *manager, */ isc_result_t +isc_socket_fdwatchpoke(isc_socket_t *sock, + int flags); +/*%< + * Poke a file descriptor watch socket informing the manager that it + * should restart watching the socket + * + * Note: + * + *\li 'sock' is the socket returned by isc_socket_fdwatchcreate + * + *\li 'flags' indicates what the manager should watch for on the socket + * in addition to what it may already be watching. It can be one or + * both of ISC_SOCKFDWATCH_READ and ISC_SOCKFDWATCH_WRITE. To + * temporarily disable watching on a socket the value indicating + * no more data should be returned from the call back routine. + * + *\li This function is not available on Windows. + * + * Requires: + * + *\li 'sock' is a valid isc socket + * + * + * Returns: + * + *\li #ISC_R_SUCCESS + */ + +isc_result_t isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, @@ -821,6 +929,10 @@ isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region, /*@}*/ isc_result_t +isc_socketmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, + isc_socketmgr_t **managerp); + +isc_result_t isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp); isc_result_t @@ -831,6 +943,8 @@ isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, * maximum number of sockets that the created manager should handle. * isc_socketmgr_create() is equivalent of isc_socketmgr_create2() with * "maxsocks" being zero. + * isc_socketmgr_createinctx() also associates the new manager with the + * specified application context. * * Notes: * @@ -842,6 +956,8 @@ isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, * *\li 'managerp' points to a NULL isc_socketmgr_t. * + *\li 'actx' is a valid application context (for createinctx()). + * * Ensures: * *\li '*managerp' is a valid isc_socketmgr_t. @@ -992,6 +1108,12 @@ isc__socketmgr_setreserved(isc_socketmgr_t *mgr, isc_uint32_t); * Temporary. For use by named only. */ +void +isc__socketmgr_maxudp(isc_socketmgr_t *mgr, int maxudp); +/*%< + * Test interface. Drop UDP packet > 'maxudp'. + */ + #ifdef HAVE_LIBXML2 void @@ -1002,6 +1124,31 @@ isc_socketmgr_renderxml(isc_socketmgr_t *mgr, xmlTextWriterPtr writer); #endif /* HAVE_LIBXML2 */ +#ifdef USE_SOCKETIMPREGISTER +/*%< + * See isc_socketmgr_create() above. + */ +typedef isc_result_t +(*isc_socketmgrcreatefunc_t)(isc_mem_t *mctx, isc_socketmgr_t **managerp); + +isc_result_t +isc_socket_register(isc_socketmgrcreatefunc_t createfunc); +/*%< + * Register a new socket I/O implementation and add it to the list of + * supported implementations. This function must be called when a different + * event library is used than the one contained in the ISC library. + */ + +isc_result_t +isc__socket_register(void); +/*%< + * A short cut function that specifies the socket I/O module in the ISC + * library for isc_socket_register(). An application that uses the ISC library + * usually do not have to care about this function: it would call + * isc_lib_register(), which internally calls this function. + */ +#endif /* USE_SOCKETIMPREGISTER */ + ISC_LANG_ENDDECLS #endif /* ISC_SOCKET_H */ diff --git a/lib/isc/include/isc/stats.h b/lib/isc/include/isc/stats.h index 1148a16..226bc08 100644 --- a/lib/isc/include/isc/stats.h +++ b/lib/isc/include/isc/stats.h @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: stats.h,v 1.4.2.2 2009-01-29 23:47:44 tbox Exp $ */ +/* $Id: stats.h,v 1.4 2009-01-29 01:03:56 jinmei Exp $ */ #ifndef ISC_STATS_H #define ISC_STATS_H 1 diff --git a/lib/isc/include/isc/symtab.h b/lib/isc/include/isc/symtab.h index a1d7102..c61d0ea 100644 --- a/lib/isc/include/isc/symtab.h +++ b/lib/isc/include/isc/symtab.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: symtab.h,v 1.24.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: symtab.h,v 1.26 2009-01-18 23:48:14 tbox Exp $ */ #ifndef ISC_SYMTAB_H #define ISC_SYMTAB_H 1 diff --git a/lib/isc/include/isc/task.h b/lib/isc/include/isc/task.h index a8c7569..a2a1bbe 100644 --- a/lib/isc/include/isc/task.h +++ b/lib/isc/include/isc/task.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: task.h,v 1.61.332.4 2010-12-03 23:45:47 tbox Exp $ */ +/* $Id: task.h,v 1.69.14.1.2.1 2011-06-02 23:47:36 tbox Exp $ */ #ifndef ISC_TASK_H #define ISC_TASK_H 1 @@ -96,6 +96,72 @@ ISC_LANG_BEGINDECLS +/*** + *** Types + ***/ + +/*% Task and task manager methods */ +typedef struct isc_taskmgrmethods { + void (*destroy)(isc_taskmgr_t **managerp); + isc_result_t (*taskcreate)(isc_taskmgr_t *manager, + unsigned int quantum, + isc_task_t **taskp); +} isc_taskmgrmethods_t; + +typedef struct isc_taskmethods { + void (*attach)(isc_task_t *source, isc_task_t **targetp); + void (*detach)(isc_task_t **taskp); + void (*destroy)(isc_task_t **taskp); + void (*send)(isc_task_t *task, isc_event_t **eventp); + void (*sendanddetach)(isc_task_t **taskp, isc_event_t **eventp); + unsigned int (*unsend)(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag, isc_eventlist_t *events); + isc_result_t (*onshutdown)(isc_task_t *task, isc_taskaction_t action, + const void *arg); + void (*shutdown)(isc_task_t *task); + void (*setname)(isc_task_t *task, const char *name, void *tag); + unsigned int (*purgeevents)(isc_task_t *task, void *sender, + isc_eventtype_t type, void *tag); + unsigned int (*purgerange)(isc_task_t *task, void *sender, + isc_eventtype_t first, isc_eventtype_t last, + void *tag); + isc_result_t (*beginexclusive)(isc_task_t *task); + void (*endexclusive)(isc_task_t *task); +} isc_taskmethods_t; + +/*% + * This structure is actually just the common prefix of a task manager + * object implementation's version of an isc_taskmgr_t. + * \brief + * Direct use of this structure by clients is forbidden. task implementations + * may change the structure. 'magic' must be ISCAPI_TASKMGR_MAGIC for any + * of the isc_task_ routines to work. task implementations must maintain + * all task invariants. + */ +struct isc_taskmgr { + unsigned int impmagic; + unsigned int magic; + isc_taskmgrmethods_t *methods; +}; + +#define ISCAPI_TASKMGR_MAGIC ISC_MAGIC('A','t','m','g') +#define ISCAPI_TASKMGR_VALID(m) ((m) != NULL && \ + (m)->magic == ISCAPI_TASKMGR_MAGIC) + +/*% + * This is the common prefix of a task object. The same note as + * that for the taskmgr structure applies. + */ +struct isc_task { + unsigned int impmagic; + unsigned int magic; + isc_taskmethods_t *methods; +}; + +#define ISCAPI_TASK_MAGIC ISC_MAGIC('A','t','s','t') +#define ISCAPI_TASK_VALID(s) ((s) != NULL && \ + (s)->magic == ISCAPI_TASK_MAGIC) + isc_result_t isc_task_create(isc_taskmgr_t *manager, unsigned int quantum, isc_task_t **taskp); @@ -550,10 +616,15 @@ isc_task_exiting(isc_task_t *t); *****/ isc_result_t +isc_taskmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, + unsigned int workers, unsigned int default_quantum, + isc_taskmgr_t **managerp); +isc_result_t isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, unsigned int default_quantum, isc_taskmgr_t **managerp); /*%< - * Create a new task manager. + * Create a new task manager. isc_taskmgr_createinctx() also associates + * the new manager with the specified application context. * * Notes: * @@ -575,6 +646,8 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, * *\li managerp != NULL && *managerp == NULL * + *\li 'actx' is a valid application context (for createinctx()). + * * Ensures: * *\li On success, '*managerp' will be attached to the newly created task @@ -584,8 +657,10 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, * *\li #ISC_R_SUCCESS *\li #ISC_R_NOMEMORY - *\li #ISC_R_NOTHREADS No threads could be created. + *\li #ISC_R_NOTHREADS No threads could be created. *\li #ISC_R_UNEXPECTED An unexpected error occurred. + *\li #ISC_R_SHUTTINGDOWN The non-threaded, shared, task + * manager shutting down. */ void @@ -629,6 +704,31 @@ isc_taskmgr_renderxml(isc_taskmgr_t *mgr, xmlTextWriterPtr writer); #endif +/*%< + * See isc_taskmgr_create() above. + */ +typedef isc_result_t +(*isc_taskmgrcreatefunc_t)(isc_mem_t *mctx, unsigned int workers, + unsigned int default_quantum, + isc_taskmgr_t **managerp); + +isc_result_t +isc_task_register(isc_taskmgrcreatefunc_t createfunc); +/*%< + * Register a new task management implementation and add it to the list of + * supported implementations. This function must be called when a different + * event library is used than the one contained in the ISC library. + */ + +isc_result_t +isc__task_register(void); +/*%< + * A short cut function that specifies the task management module in the ISC + * library for isc_task_register(). An application that uses the ISC library + * usually do not have to care about this function: it would call + * isc_lib_register(), which internally calls this function. + */ + ISC_LANG_ENDDECLS #endif /* ISC_TASK_H */ diff --git a/lib/isc/include/isc/timer.h b/lib/isc/include/isc/timer.h index 052e25b..a54e73b 100644 --- a/lib/isc/include/isc/timer.h +++ b/lib/isc/include/isc/timer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: timer.h,v 1.40 2008-06-23 23:47:11 tbox Exp $ */ +/* $Id: timer.h,v 1.43 2009-09-02 23:48:03 tbox Exp $ */ #ifndef ISC_TIMER_H #define ISC_TIMER_H 1 @@ -103,6 +103,61 @@ typedef struct isc_timerevent { #define ISC_TIMEREVENT_LIFE (ISC_EVENTCLASS_TIMER + 3) #define ISC_TIMEREVENT_LASTEVENT (ISC_EVENTCLASS_TIMER + 65535) +/*% Timer and timer manager methods */ +typedef struct { + void (*destroy)(isc_timermgr_t **managerp); + isc_result_t (*timercreate)(isc_timermgr_t *manager, + isc_timertype_t type, + isc_time_t *expires, + isc_interval_t *interval, + isc_task_t *task, + isc_taskaction_t action, + const void *arg, + isc_timer_t **timerp); +} isc_timermgrmethods_t; + +typedef struct { + void (*attach)(isc_timer_t *timer, isc_timer_t **timerp); + void (*detach)(isc_timer_t **timerp); + isc_result_t (*reset)(isc_timer_t *timer, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_boolean_t purge); + isc_result_t (*touch)(isc_timer_t *timer); +} isc_timermethods_t; + +/*% + * This structure is actually just the common prefix of a timer manager + * object implementation's version of an isc_timermgr_t. + * \brief + * Direct use of this structure by clients is forbidden. timer implementations + * may change the structure. 'magic' must be ISCAPI_TIMERMGR_MAGIC for any + * of the isc_timer_ routines to work. timer implementations must maintain + * all timer invariants. + */ +struct isc_timermgr { + unsigned int impmagic; + unsigned int magic; + isc_timermgrmethods_t *methods; +}; + +#define ISCAPI_TIMERMGR_MAGIC ISC_MAGIC('A','t','m','g') +#define ISCAPI_TIMERMGR_VALID(m) ((m) != NULL && \ + (m)->magic == ISCAPI_TIMERMGR_MAGIC) + +/*% + * This is the common prefix of a timer object. The same note as + * that for the timermgr structure applies. + */ +struct isc_timer { + unsigned int impmagic; + unsigned int magic; + isc_timermethods_t *methods; +}; + +#define ISCAPI_TIMER_MAGIC ISC_MAGIC('A','t','m','r') +#define ISCAPI_TIMER_VALID(s) ((s) != NULL && \ + (s)->magic == ISCAPI_TIMER_MAGIC) + /*** *** Timer and Timer Manager Functions *** @@ -289,9 +344,14 @@ isc_timer_gettype(isc_timer_t *timer); */ isc_result_t +isc_timermgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, + isc_timermgr_t **managerp); + +isc_result_t isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp); /*%< - * Create a timer manager. + * Create a timer manager. isc_timermgr_createinctx() also associates + * the new manager with the specified application context. * * Notes: * @@ -303,6 +363,8 @@ isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp); * *\li 'managerp' points to a NULL isc_timermgr_t. * + *\li 'actx' is a valid application context (for createinctx()). + * * Ensures: * *\li '*managerp' is a valid isc_timermgr_t. @@ -339,6 +401,31 @@ isc_timermgr_destroy(isc_timermgr_t **managerp); void isc_timermgr_poke(isc_timermgr_t *m); +#ifdef USE_TIMERIMPREGISTER +/*%< + * See isc_timermgr_create() above. + */ +typedef isc_result_t +(*isc_timermgrcreatefunc_t)(isc_mem_t *mctx, isc_timermgr_t **managerp); + +isc_result_t +isc__timer_register(void); +/*%< + * Register a new timer management implementation and add it to the list of + * supported implementations. This function must be called when a different + * event library is used than the one contained in the ISC library. + */ + +isc_result_t +isc_timer_register(isc_timermgrcreatefunc_t createfunc); +/*%< + * A short cut function that specifies the timer management module in the ISC + * library for isc_timer_register(). An application that uses the ISC library + * usually do not have to care about this function: it would call + * isc_lib_register(), which internally calls this function. + */ +#endif /* USE_TIMERIMPREGISTER */ + ISC_LANG_ENDDECLS #endif /* ISC_TIMER_H */ diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h index 01362b8..10da62b 100644 --- a/lib/isc/include/isc/types.h +++ b/lib/isc/include/isc/types.h @@ -15,11 +15,14 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.46.84.2 2009-01-29 23:47:44 tbox Exp $ */ +/* $Id: types.h,v 1.52 2009-12-05 23:31:41 each Exp $ */ #ifndef ISC_TYPES_H #define ISC_TYPES_H 1 +#include +#include + /*! \file isc/types.h * \brief * OS-specific types, from the OS-specific include directories. @@ -40,6 +43,8 @@ /* Core Types. Alphabetized by defined type. */ +typedef struct isc_appctx isc_appctx_t; /*%< Application context */ +typedef struct isc_backtrace_symmap isc_backtrace_symmap_t; /*%< Symbol Table Entry */ typedef struct isc_bitstring isc_bitstring_t; /*%< Bitstring */ typedef struct isc_buffer isc_buffer_t; /*%< Buffer */ typedef ISC_LIST(isc_buffer_t) isc_bufferlist_t; /*%< Buffer List */ @@ -94,7 +99,7 @@ typedef struct isc_timer isc_timer_t; /*%< Timer */ typedef struct isc_timermgr isc_timermgr_t; /*%< Timer Manager */ typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *); -typedef int (*isc_sockfdwatch_t)(isc_task_t *, isc_socket_t *, void *); +typedef int (*isc_sockfdwatch_t)(isc_task_t *, isc_socket_t *, void *, int); /* The following cannot be listed alphabetically due to forward reference */ typedef isc_result_t (isc_httpdaction_t)(const char *url, diff --git a/lib/isc/include/isc/util.h b/lib/isc/include/isc/util.h index 8ccad8d..11d0044 100644 --- a/lib/isc/include/isc/util.h +++ b/lib/isc/include/isc/util.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: util.h,v 1.30.332.2 2010-01-11 23:47:22 tbox Exp $ */ +/* $Id: util.h,v 1.32 2010-01-11 23:48:37 tbox Exp $ */ #ifndef ISC_UTIL_H #define ISC_UTIL_H 1 diff --git a/lib/isc/inet_aton.c b/lib/isc/inet_aton.c index 3c25ca3..9e35a36 100644 --- a/lib/isc/inet_aton.c +++ b/lib/isc/inet_aton.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1996-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -71,7 +71,7 @@ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; -static char rcsid[] = "$Id: inet_aton.c,v 1.21.332.2 2009-03-05 23:47:03 tbox Exp $"; +static char rcsid[] = "$Id: inet_aton.c,v 1.23 2008-12-01 23:47:45 tbox Exp $"; #endif /* LIBC_SCCS and not lint */ #include diff --git a/lib/isc/inet_ntop.c b/lib/isc/inet_ntop.c index 22930f3..581ebe8 100644 --- a/lib/isc/inet_ntop.c +++ b/lib/isc/inet_ntop.c @@ -19,7 +19,7 @@ #if defined(LIBC_SCCS) && !defined(lint) static char rcsid[] = - "$Id: inet_ntop.c,v 1.19.332.2 2009-07-18 23:47:25 tbox Exp $"; + "$Id: inet_ntop.c,v 1.21 2009-07-17 23:47:41 tbox Exp $"; #endif /* LIBC_SCCS and not lint */ #include diff --git a/lib/isc/iterated_hash.c b/lib/isc/iterated_hash.c index ebc5076..7185075 100644 --- a/lib/isc/iterated_hash.c +++ b/lib/isc/iterated_hash.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: iterated_hash.c,v 1.4.48.2 2009-02-18 23:47:12 tbox Exp $ */ +/* $Id: iterated_hash.c,v 1.6 2009-02-18 23:47:48 tbox Exp $ */ #include "config.h" diff --git a/lib/isc/lib.c b/lib/isc/lib.c index 99b0178..1b6ccc0 100644 --- a/lib/isc/lib.c +++ b/lib/isc/lib.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lib.c,v 1.14 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: lib.c,v 1.16 2009-09-02 23:48:02 tbox Exp $ */ /*! \file */ @@ -24,9 +24,15 @@ #include #include -#include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include /*** *** Globals @@ -41,7 +47,6 @@ LIBISC_EXTERNAL_DATA isc_msgcat_t * isc_msgcat = NULL; static isc_once_t msgcat_once = ISC_ONCE_INIT; - /*** *** Functions ***/ @@ -77,3 +82,22 @@ isc_lib_initmsgcat(void) { abort(); } } + +#ifndef BIND9 +static isc_once_t register_once = ISC_ONCE_INIT; + +static void +do_register(void) { + RUNTIME_CHECK(isc__mem_register() == ISC_R_SUCCESS); + RUNTIME_CHECK(isc__app_register() == ISC_R_SUCCESS); + RUNTIME_CHECK(isc__task_register() == ISC_R_SUCCESS); + RUNTIME_CHECK(isc__socket_register() == ISC_R_SUCCESS); + RUNTIME_CHECK(isc__timer_register() == ISC_R_SUCCESS); +} + +void +isc_lib_register() { + RUNTIME_CHECK(isc_once_do(®ister_once, do_register) + == ISC_R_SUCCESS); +} +#endif diff --git a/lib/isc/log.c b/lib/isc/log.c index 121bd25..7ef6692 100644 --- a/lib/isc/log.c +++ b/lib/isc/log.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: log.c,v 1.94.332.5 2009-02-16 02:04:05 marka Exp $ */ +/* $Id: log.c,v 1.99 2009-02-16 02:01:16 marka Exp $ */ /*! \file * \author Principal Authors: DCL */ diff --git a/lib/isc/md5.c b/lib/isc/md5.c index b9ec42c..b778177 100644 --- a/lib/isc/md5.c +++ b/lib/isc/md5.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: md5.c,v 1.14 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: md5.c,v 1.16 2009-02-06 23:47:42 tbox Exp $ */ /*! \file * This code implements the MD5 message-digest algorithm. @@ -38,10 +38,35 @@ #include #include +#include #include #include #include +#ifdef ISC_PLATFORM_OPENSSLHASH + +void +isc_md5_init(isc_md5_t *ctx) { + EVP_DigestInit(ctx, EVP_md5()); +} + +void +isc_md5_invalidate(isc_md5_t *ctx) { + EVP_MD_CTX_cleanup(ctx); +} + +void +isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len) { + EVP_DigestUpdate(ctx, (const void *) buf, (size_t) len); +} + +void +isc_md5_final(isc_md5_t *ctx, unsigned char *digest) { + EVP_DigestFinal(ctx, digest, NULL); +} + +#else + static void byteSwap(isc_uint32_t *buf, unsigned words) { @@ -249,3 +274,4 @@ isc_md5_final(isc_md5_t *ctx, unsigned char *digest) { memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(isc_md5_t)); /* In case it's sensitive */ } +#endif diff --git a/lib/isc/mem.c b/lib/isc/mem.c index aeacfc0..8311569 100644 --- a/lib/isc/mem.c +++ b/lib/isc/mem.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mem.c,v 1.145.120.9 2010-08-11 23:45:49 tbox Exp $ */ +/* $Id: mem.c,v 1.160 2010-12-08 02:46:16 marka Exp $ */ /*! \file */ @@ -60,6 +60,9 @@ LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING; /* * Types. */ +typedef struct isc__mem isc__mem_t; +typedef struct isc__mempool isc__mempool_t; + #if ISC_MEM_TRACKLINES typedef struct debuglink debuglink_t; struct debuglink { @@ -89,7 +92,7 @@ typedef struct { */ union { size_t size; - isc_mem_t *ctx; + isc__mem_t *ctx; char bytes[ALIGNMENT_SIZE]; } u; } size_info; @@ -110,7 +113,7 @@ typedef ISC_LIST(debuglink_t) debuglist_t; /* List of all active memory contexts. */ -static ISC_LIST(isc_mem_t) contexts; +static ISC_LIST(isc__mem_t) contexts; static isc_once_t once = ISC_ONCE_INIT; static isc_mutex_t lock; @@ -120,8 +123,8 @@ static isc_mutex_t lock; */ static isc_uint64_t totallost; -struct isc_mem { - unsigned int magic; +struct isc__mem { + isc_mem_t common; isc_ondestroy_t ondestroy; unsigned int flags; isc_mutex_t lock; @@ -144,7 +147,7 @@ struct isc_mem { isc_boolean_t is_overmem; isc_mem_water_t water; void * water_arg; - ISC_LIST(isc_mempool_t) pools; + ISC_LIST(isc__mempool_t) pools; unsigned int poolcnt; /* ISC_MEMFLAG_INTERNAL */ @@ -163,19 +166,19 @@ struct isc_mem { #endif unsigned int memalloc_failures; - ISC_LINK(isc_mem_t) link; + ISC_LINK(isc__mem_t) link; }; #define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p') #define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC) -struct isc_mempool { +struct isc__mempool { /* always unlocked */ - unsigned int magic; /*%< magic number */ + isc_mempool_t common; /*%< common header of mempool's */ isc_mutex_t *lock; /*%< optional lock */ - isc_mem_t *mctx; /*%< our memory context */ + isc__mem_t *mctx; /*%< our memory context */ /*%< locked via the memory context's lock */ - ISC_LINK(isc_mempool_t) link; /*%< next pool in this mem context */ + ISC_LINK(isc__mempool_t) link; /*%< next pool in this mem context */ /*%< optionally locked from here down */ element *items; /*%< low water item list */ size_t size; /*%< size of each item on this pool */ @@ -210,13 +213,187 @@ struct isc_mempool { #define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e) static void -print_active(isc_mem_t *ctx, FILE *out); +print_active(isc__mem_t *ctx, FILE *out); + +/*% + * The following can be either static or public, depending on build environment. + */ + +#ifdef BIND9 +#define ISC_MEMFUNC_SCOPE +#else +#define ISC_MEMFUNC_SCOPE static +#endif + +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_createx(size_t init_max_size, size_t target_size, + isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, + isc_mem_t **ctxp); +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_createx2(size_t init_max_size, size_t target_size, + isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, + isc_mem_t **ctxp, unsigned int flags); +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp); +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_create2(size_t init_max_size, size_t target_size, + isc_mem_t **ctxp, unsigned int flags); +ISC_MEMFUNC_SCOPE void +isc__mem_attach(isc_mem_t *source, isc_mem_t **targetp); +ISC_MEMFUNC_SCOPE void +isc__mem_detach(isc_mem_t **ctxp); +ISC_MEMFUNC_SCOPE void +isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG); +ISC_MEMFUNC_SCOPE void +isc__mem_destroy(isc_mem_t **ctxp); +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event); +ISC_MEMFUNC_SCOPE void * +isc___mem_get(isc_mem_t *ctx, size_t size FLARG); +ISC_MEMFUNC_SCOPE void +isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG); +ISC_MEMFUNC_SCOPE void +isc__mem_stats(isc_mem_t *ctx, FILE *out); +ISC_MEMFUNC_SCOPE void * +isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG); +ISC_MEMFUNC_SCOPE void * +isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG); +ISC_MEMFUNC_SCOPE void +isc___mem_free(isc_mem_t *ctx, void *ptr FLARG); +ISC_MEMFUNC_SCOPE char * +isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG); +ISC_MEMFUNC_SCOPE void +isc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag); +ISC_MEMFUNC_SCOPE void +isc__mem_setquota(isc_mem_t *ctx, size_t quota); +ISC_MEMFUNC_SCOPE size_t +isc__mem_getquota(isc_mem_t *ctx); +ISC_MEMFUNC_SCOPE size_t +isc__mem_inuse(isc_mem_t *ctx); +ISC_MEMFUNC_SCOPE isc_boolean_t +isc__mem_isovermem(isc_mem_t *ctx); +ISC_MEMFUNC_SCOPE void +isc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg, + size_t hiwater, size_t lowater); +ISC_MEMFUNC_SCOPE void +isc__mem_waterack(isc_mem_t *ctx0, int flag); +ISC_MEMFUNC_SCOPE void +isc__mem_setname(isc_mem_t *ctx, const char *name, void *tag); +ISC_MEMFUNC_SCOPE const char * +isc__mem_getname(isc_mem_t *ctx); +ISC_MEMFUNC_SCOPE void * +isc__mem_gettag(isc_mem_t *ctx); +ISC_MEMFUNC_SCOPE isc_result_t +isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp); +ISC_MEMFUNC_SCOPE void +isc__mempool_setname(isc_mempool_t *mpctx, const char *name); +ISC_MEMFUNC_SCOPE void +isc__mempool_destroy(isc_mempool_t **mpctxp); +ISC_MEMFUNC_SCOPE void +isc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock); +ISC_MEMFUNC_SCOPE void * +isc___mempool_get(isc_mempool_t *mpctx FLARG); +ISC_MEMFUNC_SCOPE void +isc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG); +ISC_MEMFUNC_SCOPE void +isc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit); +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getfreemax(isc_mempool_t *mpctx); +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getfreecount(isc_mempool_t *mpctx); +ISC_MEMFUNC_SCOPE void +isc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit); +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getmaxalloc(isc_mempool_t *mpctx); +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getallocated(isc_mempool_t *mpctx); +ISC_MEMFUNC_SCOPE void +isc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit); +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getfillcount(isc_mempool_t *mpctx); +#ifdef BIND9 +ISC_MEMFUNC_SCOPE void +isc__mem_printactive(isc_mem_t *ctx0, FILE *file); +ISC_MEMFUNC_SCOPE void +isc__mem_printallactive(FILE *file); +ISC_MEMFUNC_SCOPE void +isc__mem_checkdestroyed(FILE *file); +ISC_MEMFUNC_SCOPE unsigned int +isc__mem_references(isc_mem_t *ctx0); +#endif + +static struct isc__memmethods { + isc_memmethods_t methods; + + /*% + * The following are defined just for avoiding unused static functions. + */ +#ifndef BIND9 + void *createx, *create, *create2, *ondestroy, *stats, + *setquota, *getquota, *setname, *getname, *gettag; +#endif +} memmethods = { + { + isc__mem_attach, + isc__mem_detach, + isc__mem_destroy, + isc___mem_get, + isc___mem_put, + isc___mem_putanddetach, + isc___mem_allocate, + isc___mem_reallocate, + isc___mem_strdup, + isc___mem_free, + isc__mem_setdestroycheck, + isc__mem_setwater, + isc__mem_waterack, + isc__mem_inuse, + isc__mem_isovermem, + isc__mempool_create + } +#ifndef BIND9 + , + (void *)isc__mem_createx, (void *)isc__mem_create, + (void *)isc__mem_create2, (void *)isc__mem_ondestroy, + (void *)isc__mem_stats, (void *)isc__mem_setquota, + (void *)isc__mem_getquota, (void *)isc__mem_setname, + (void *)isc__mem_getname, (void *)isc__mem_gettag +#endif +}; + +static struct isc__mempoolmethods { + isc_mempoolmethods_t methods; + + /*% + * The following are defined just for avoiding unused static functions. + */ +#ifndef BIND9 + void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount; +#endif +} mempoolmethods = { + { + isc__mempool_destroy, + isc___mempool_get, + isc___mempool_put, + isc__mempool_getallocated, + isc__mempool_setmaxalloc, + isc__mempool_setfreemax, + isc__mempool_setname, + isc__mempool_associatelock, + isc__mempool_setfillcount + } +#ifndef BIND9 + , + (void *)isc__mempool_getfreemax, (void *)isc__mempool_getfreecount, + (void *)isc__mempool_getmaxalloc, (void *)isc__mempool_getfillcount +#endif +}; /*! * mctx must be locked. */ static inline void -add_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size +add_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size FLARG) { debuglink_t *dl; @@ -276,7 +453,7 @@ add_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size } static inline void -delete_trace_entry(isc_mem_t *mctx, const void *ptr, unsigned int size, +delete_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size, const char *file, unsigned int line) { debuglink_t *dl; @@ -347,7 +524,7 @@ quantize(size_t size) { } static inline isc_boolean_t -more_basic_blocks(isc_mem_t *ctx) { +more_basic_blocks(isc__mem_t *ctx) { void *new; unsigned char *curr, *next; unsigned char *first, *last; @@ -417,7 +594,7 @@ more_basic_blocks(isc_mem_t *ctx) { } static inline isc_boolean_t -more_frags(isc_mem_t *ctx, size_t new_size) { +more_frags(isc__mem_t *ctx, size_t new_size) { int i, frags; size_t total_size; void *new; @@ -479,7 +656,7 @@ more_frags(isc_mem_t *ctx, size_t new_size) { } static inline void * -mem_getunlocked(isc_mem_t *ctx, size_t size) { +mem_getunlocked(isc__mem_t *ctx, size_t size) { size_t new_size = quantize(size); void *ret; @@ -560,7 +737,7 @@ check_overrun(void *mem, size_t size, size_t new_size) { #endif static inline void -mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) { +mem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) { size_t new_size = quantize(size); if (size == ctx->max_size || new_size >= ctx->max_size) { @@ -608,7 +785,7 @@ mem_putunlocked(isc_mem_t *ctx, void *mem, size_t size) { * Perform a malloc, doing memory filling and overrun detection as necessary. */ static inline void * -mem_get(isc_mem_t *ctx, size_t size) { +mem_get(isc__mem_t *ctx, size_t size) { char *ret; #if ISC_MEM_CHECKOVERRUN @@ -636,7 +813,7 @@ mem_get(isc_mem_t *ctx, size_t size) { * Perform a free, doing memory filling and overrun detection as necessary. */ static inline void -mem_put(isc_mem_t *ctx, void *mem, size_t size) { +mem_put(isc__mem_t *ctx, void *mem, size_t size) { #if ISC_MEM_CHECKOVERRUN INSIST(((unsigned char *)mem)[size] == 0xbe); #endif @@ -652,7 +829,7 @@ mem_put(isc_mem_t *ctx, void *mem, size_t size) { * Update internal counters after a memory get. */ static inline void -mem_getstats(isc_mem_t *ctx, size_t size) { +mem_getstats(isc__mem_t *ctx, size_t size) { ctx->total += size; ctx->inuse += size; @@ -669,7 +846,7 @@ mem_getstats(isc_mem_t *ctx, size_t size) { * Update internal counters after a memory put. */ static inline void -mem_putstats(isc_mem_t *ctx, void *ptr, size_t size) { +mem_putstats(isc__mem_t *ctx, void *ptr, size_t size) { UNUSED(ptr); INSIST(ctx->inuse >= size); @@ -713,22 +890,22 @@ initialize_action(void) { * Public. */ -isc_result_t -isc_mem_createx(size_t init_max_size, size_t target_size, - isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, - isc_mem_t **ctxp) +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_createx(size_t init_max_size, size_t target_size, + isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, + isc_mem_t **ctxp) { - return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree, - arg, ctxp, ISC_MEMFLAG_DEFAULT)); + return (isc__mem_createx2(init_max_size, target_size, memalloc, memfree, + arg, ctxp, ISC_MEMFLAG_DEFAULT)); } -isc_result_t -isc_mem_createx2(size_t init_max_size, size_t target_size, - isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, - isc_mem_t **ctxp, unsigned int flags) +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_createx2(size_t init_max_size, size_t target_size, + isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, + isc_mem_t **ctxp, unsigned int flags) { - isc_mem_t *ctx; + isc__mem_t *ctx; isc_result_t result; REQUIRE(ctxp != NULL && *ctxp == NULL); @@ -769,7 +946,9 @@ isc_mem_createx2(size_t init_max_size, size_t target_size, ctx->is_overmem = ISC_FALSE; ctx->water = NULL; ctx->water_arg = NULL; - ctx->magic = MEM_MAGIC; + ctx->common.impmagic = MEM_MAGIC; + ctx->common.magic = ISCAPI_MCTX_MAGIC; + ctx->common.methods = (isc_memmethods_t *)&memmethods; isc_ondestroy_init(&ctx->ondestroy); ctx->memalloc = memalloc; ctx->memfree = memfree; @@ -834,7 +1013,7 @@ isc_mem_createx2(size_t init_max_size, size_t target_size, ISC_LIST_INITANDAPPEND(contexts, ctx, link); UNLOCK(&lock); - *ctxp = ctx; + *ctxp = (isc_mem_t *)ctx; return (ISC_R_SUCCESS); error: @@ -855,26 +1034,24 @@ isc_mem_createx2(size_t init_max_size, size_t target_size, return (result); } -isc_result_t -isc_mem_create(size_t init_max_size, size_t target_size, - isc_mem_t **ctxp) -{ - return (isc_mem_createx2(init_max_size, target_size, - default_memalloc, default_memfree, NULL, - ctxp, ISC_MEMFLAG_DEFAULT)); +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp) { + return (isc__mem_createx2(init_max_size, target_size, + default_memalloc, default_memfree, NULL, + ctxp, ISC_MEMFLAG_DEFAULT)); } -isc_result_t -isc_mem_create2(size_t init_max_size, size_t target_size, - isc_mem_t **ctxp, unsigned int flags) +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_create2(size_t init_max_size, size_t target_size, + isc_mem_t **ctxp, unsigned int flags) { - return (isc_mem_createx2(init_max_size, target_size, - default_memalloc, default_memfree, NULL, - ctxp, flags)); + return (isc__mem_createx2(init_max_size, target_size, + default_memalloc, default_memfree, NULL, + ctxp, flags)); } static void -destroy(isc_mem_t *ctx) { +destroy(isc__mem_t *ctx) { unsigned int i; isc_ondestroy_t ondest; @@ -883,7 +1060,8 @@ destroy(isc_mem_t *ctx) { totallost += ctx->inuse; UNLOCK(&lock); - ctx->magic = 0; + ctx->common.impmagic = 0; + ctx->common.magic = 0; INSIST(ISC_LIST_EMPTY(ctx->pools)); @@ -941,8 +1119,10 @@ destroy(isc_mem_t *ctx) { isc_ondestroy_notify(&ondest, ctx); } -void -isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) { +ISC_MEMFUNC_SCOPE void +isc__mem_attach(isc_mem_t *source0, isc_mem_t **targetp) { + isc__mem_t *source = (isc__mem_t *)source0; + REQUIRE(VALID_CONTEXT(source)); REQUIRE(targetp != NULL && *targetp == NULL); @@ -950,16 +1130,16 @@ isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) { source->references++; MCTXUNLOCK(source, &source->lock); - *targetp = source; + *targetp = (isc_mem_t *)source; } -void -isc_mem_detach(isc_mem_t **ctxp) { - isc_mem_t *ctx; +ISC_MEMFUNC_SCOPE void +isc__mem_detach(isc_mem_t **ctxp) { + isc__mem_t *ctx; isc_boolean_t want_destroy = ISC_FALSE; REQUIRE(ctxp != NULL); - ctx = *ctxp; + ctx = (isc__mem_t *)*ctxp; REQUIRE(VALID_CONTEXT(ctx)); MCTXLOCK(ctx, &ctx->lock); @@ -985,15 +1165,15 @@ isc_mem_detach(isc_mem_t **ctxp) { * isc_mem_detach(&mctx); */ -void -isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { - isc_mem_t *ctx; +ISC_MEMFUNC_SCOPE void +isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { + isc__mem_t *ctx; isc_boolean_t want_destroy = ISC_FALSE; size_info *si; size_t oldsize; REQUIRE(ctxp != NULL); - ctx = *ctxp; + ctx = (isc__mem_t *)*ctxp; REQUIRE(VALID_CONTEXT(ctx)); REQUIRE(ptr != NULL); @@ -1011,7 +1191,7 @@ isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { oldsize -= ALIGNMENT_SIZE; INSIST(oldsize == size); } - isc__mem_free(ctx, ptr FLARG_PASS); + isc_mem_free((isc_mem_t *)ctx, ptr); MCTXLOCK(ctx, &ctx->lock); ctx->references--; @@ -1045,9 +1225,9 @@ isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { destroy(ctx); } -void -isc_mem_destroy(isc_mem_t **ctxp) { - isc_mem_t *ctx; +ISC_MEMFUNC_SCOPE void +isc__mem_destroy(isc_mem_t **ctxp) { + isc__mem_t *ctx; /* * This routine provides legacy support for callers who use mctxs @@ -1055,7 +1235,7 @@ isc_mem_destroy(isc_mem_t **ctxp) { */ REQUIRE(ctxp != NULL); - ctx = *ctxp; + ctx = (isc__mem_t *)*ctxp; REQUIRE(VALID_CONTEXT(ctx)); MCTXLOCK(ctx, &ctx->lock); @@ -1072,8 +1252,9 @@ isc_mem_destroy(isc_mem_t **ctxp) { *ctxp = NULL; } -isc_result_t -isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) { +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_ondestroy(isc_mem_t *ctx0, isc_task_t *task, isc_event_t **event) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; isc_result_t res; MCTXLOCK(ctx, &ctx->lock); @@ -1083,16 +1264,16 @@ isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) { return (res); } - -void * -isc__mem_get(isc_mem_t *ctx, size_t size FLARG) { +ISC_MEMFUNC_SCOPE void * +isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; void *ptr; isc_boolean_t call_water = ISC_FALSE; REQUIRE(VALID_CONTEXT(ctx)); if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) - return (isc__mem_allocate(ctx, size FLARG_PASS)); + return (isc__mem_allocate(ctx0, size FLARG_PASS)); if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { MCTXLOCK(ctx, &ctx->lock); @@ -1128,9 +1309,9 @@ isc__mem_get(isc_mem_t *ctx, size_t size FLARG) { return (ptr); } -void -isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG) -{ +ISC_MEMFUNC_SCOPE void +isc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; isc_boolean_t call_water = ISC_FALSE; size_info *si; size_t oldsize; @@ -1146,7 +1327,7 @@ isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG) oldsize -= ALIGNMENT_SIZE; INSIST(oldsize == size); } - isc__mem_free(ctx, ptr FLARG_PASS); + isc_mem_free((isc_mem_t *)ctx, ptr); return; } @@ -1181,8 +1362,10 @@ isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG) (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); } -void -isc_mem_waterack(isc_mem_t *ctx, int flag) { +ISC_MEMFUNC_SCOPE void +isc__mem_waterack(isc_mem_t *ctx0, int flag) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + REQUIRE(VALID_CONTEXT(ctx)); MCTXLOCK(ctx, &ctx->lock); @@ -1195,7 +1378,7 @@ isc_mem_waterack(isc_mem_t *ctx, int flag) { #if ISC_MEM_TRACKLINES static void -print_active(isc_mem_t *mctx, FILE *out) { +print_active(isc__mem_t *mctx, FILE *out) { if (mctx->debuglist != NULL) { debuglink_t *dl; unsigned int i, j; @@ -1237,11 +1420,12 @@ print_active(isc_mem_t *mctx, FILE *out) { /* * Print the stats[] on the stream "out" with suitable formatting. */ -void -isc_mem_stats(isc_mem_t *ctx, FILE *out) { +ISC_MEMFUNC_SCOPE void +isc__mem_stats(isc_mem_t *ctx0, FILE *out) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; size_t i; const struct stats *s; - const isc_mempool_t *pool; + const isc__mempool_t *pool; REQUIRE(VALID_CONTEXT(ctx)); MCTXLOCK(ctx, &ctx->lock); @@ -1314,7 +1498,8 @@ isc_mem_stats(isc_mem_t *ctx, FILE *out) { */ static void * -isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) { +isc__mem_allocateunlocked(isc_mem_t *ctx0, size_t size) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; size_info *si; size += ALIGNMENT_SIZE; @@ -1336,8 +1521,9 @@ isc__mem_allocateunlocked(isc_mem_t *ctx, size_t size) { return (&si[1]); } -void * -isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) { +ISC_MEMFUNC_SCOPE void * +isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; size_info *si; isc_boolean_t call_water = ISC_FALSE; @@ -1345,9 +1531,9 @@ isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) { if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { MCTXLOCK(ctx, &ctx->lock); - si = isc__mem_allocateunlocked(ctx, size); + si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size); } else { - si = isc__mem_allocateunlocked(ctx, size); + si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size); MCTXLOCK(ctx, &ctx->lock); if (si != NULL) mem_getstats(ctx, si[-1].u.size); @@ -1381,8 +1567,9 @@ isc__mem_allocate(isc_mem_t *ctx, size_t size FLARG) { return (si); } -void * -isc__mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG) { +ISC_MEMFUNC_SCOPE void * +isc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; void *new_ptr = NULL; size_t oldsize, copysize; @@ -1400,23 +1587,24 @@ isc__mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG) { * NULL if allocation fails or doesn't happen. */ if (size > 0U) { - new_ptr = isc__mem_allocate(ctx, size FLARG_PASS); + new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS); if (new_ptr != NULL && ptr != NULL) { oldsize = (((size_info *)ptr)[-1]).u.size; INSIST(oldsize >= ALIGNMENT_SIZE); oldsize -= ALIGNMENT_SIZE; copysize = oldsize > size ? size : oldsize; memcpy(new_ptr, ptr, copysize); - isc__mem_free(ctx, ptr FLARG_PASS); + isc__mem_free(ctx0, ptr FLARG_PASS); } } else if (ptr != NULL) - isc__mem_free(ctx, ptr FLARG_PASS); + isc__mem_free(ctx0, ptr FLARG_PASS); return (new_ptr); } -void -isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) { +ISC_MEMFUNC_SCOPE void +isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; size_info *si; size_t size; isc_boolean_t call_water= ISC_FALSE; @@ -1472,8 +1660,9 @@ isc__mem_free(isc_mem_t *ctx, void *ptr FLARG) { * Other useful things. */ -char * -isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) { +ISC_MEMFUNC_SCOPE char * +isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) { + isc__mem_t *mctx = (isc__mem_t *)mctx0; size_t len; char *ns; @@ -1482,7 +1671,7 @@ isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) { len = strlen(s); - ns = isc__mem_allocate(mctx, len + 1 FLARG_PASS); + ns = isc___mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS); if (ns != NULL) strncpy(ns, s, len + 1); @@ -1490,8 +1679,10 @@ isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) { return (ns); } -void -isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) { +ISC_MEMFUNC_SCOPE void +isc__mem_setdestroycheck(isc_mem_t *ctx0, isc_boolean_t flag) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + REQUIRE(VALID_CONTEXT(ctx)); MCTXLOCK(ctx, &ctx->lock); @@ -1504,8 +1695,10 @@ isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) { * Quotas */ -void -isc_mem_setquota(isc_mem_t *ctx, size_t quota) { +ISC_MEMFUNC_SCOPE void +isc__mem_setquota(isc_mem_t *ctx0, size_t quota) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + REQUIRE(VALID_CONTEXT(ctx)); MCTXLOCK(ctx, &ctx->lock); @@ -1514,8 +1707,9 @@ isc_mem_setquota(isc_mem_t *ctx, size_t quota) { MCTXUNLOCK(ctx, &ctx->lock); } -size_t -isc_mem_getquota(isc_mem_t *ctx) { +ISC_MEMFUNC_SCOPE size_t +isc__mem_getquota(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; size_t quota; REQUIRE(VALID_CONTEXT(ctx)); @@ -1528,8 +1722,9 @@ isc_mem_getquota(isc_mem_t *ctx) { return (quota); } -size_t -isc_mem_inuse(isc_mem_t *ctx) { +ISC_MEMFUNC_SCOPE size_t +isc__mem_inuse(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; size_t inuse; REQUIRE(VALID_CONTEXT(ctx)); @@ -1542,10 +1737,11 @@ isc_mem_inuse(isc_mem_t *ctx) { return (inuse); } -void -isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg, +ISC_MEMFUNC_SCOPE void +isc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg, size_t hiwater, size_t lowater) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; isc_boolean_t callwater = ISC_FALSE; isc_mem_water_t oldwater; void *oldwater_arg; @@ -1580,8 +1776,10 @@ isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg, (oldwater)(oldwater_arg, ISC_MEM_LOWATER); } -isc_boolean_t -isc_mem_isovermem(isc_mem_t *ctx) { +ISC_MEMFUNC_SCOPE isc_boolean_t +isc__mem_isovermem(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + REQUIRE(VALID_CONTEXT(ctx)); /* @@ -1592,8 +1790,10 @@ isc_mem_isovermem(isc_mem_t *ctx) { return (ctx->is_overmem); } -void -isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag) { +ISC_MEMFUNC_SCOPE void +isc__mem_setname(isc_mem_t *ctx0, const char *name, void *tag) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + REQUIRE(VALID_CONTEXT(ctx)); LOCK(&ctx->lock); @@ -1603,15 +1803,19 @@ isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag) { UNLOCK(&ctx->lock); } -const char * -isc_mem_getname(isc_mem_t *ctx) { +ISC_MEMFUNC_SCOPE const char * +isc__mem_getname(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + REQUIRE(VALID_CONTEXT(ctx)); return (ctx->name); } -void * -isc_mem_gettag(isc_mem_t *ctx) { +ISC_MEMFUNC_SCOPE void * +isc__mem_gettag(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + REQUIRE(VALID_CONTEXT(ctx)); return (ctx->tag); @@ -1621,9 +1825,10 @@ isc_mem_gettag(isc_mem_t *ctx) { * Memory pool stuff */ -isc_result_t -isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) { - isc_mempool_t *mpctx; +ISC_MEMFUNC_SCOPE isc_result_t +isc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) { + isc__mem_t *mctx = (isc__mem_t *)mctx0; + isc__mempool_t *mpctx; REQUIRE(VALID_CONTEXT(mctx)); REQUIRE(size > 0U); @@ -1633,11 +1838,13 @@ isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) { * Allocate space for this pool, initialize values, and if all works * well, attach to the memory context. */ - mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t)); + mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t)); if (mpctx == NULL) return (ISC_R_NOMEMORY); - mpctx->magic = MEMPOOL_MAGIC; + mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods; + mpctx->common.impmagic = MEMPOOL_MAGIC; + mpctx->common.magic = ISCAPI_MPOOL_MAGIC; mpctx->lock = NULL; mpctx->mctx = mctx; mpctx->size = size; @@ -1652,7 +1859,7 @@ isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) { #endif mpctx->items = NULL; - *mpctxp = mpctx; + *mpctxp = (isc_mempool_t *)mpctx; MCTXLOCK(mctx, &mctx->lock); ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link); @@ -1662,9 +1869,12 @@ isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) { return (ISC_R_SUCCESS); } -void -isc_mempool_setname(isc_mempool_t *mpctx, const char *name) { +ISC_MEMFUNC_SCOPE void +isc__mempool_setname(isc_mempool_t *mpctx0, const char *name) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + REQUIRE(name != NULL); + REQUIRE(VALID_MEMPOOL(mpctx)); #if ISC_MEMPOOL_NAMES if (mpctx->lock != NULL) @@ -1681,20 +1891,20 @@ isc_mempool_setname(isc_mempool_t *mpctx, const char *name) { #endif } -void -isc_mempool_destroy(isc_mempool_t **mpctxp) { - isc_mempool_t *mpctx; - isc_mem_t *mctx; +ISC_MEMFUNC_SCOPE void +isc__mempool_destroy(isc_mempool_t **mpctxp) { + isc__mempool_t *mpctx; + isc__mem_t *mctx; isc_mutex_t *lock; element *item; REQUIRE(mpctxp != NULL); - mpctx = *mpctxp; + mpctx = (isc__mempool_t *)*mpctxp; REQUIRE(VALID_MEMPOOL(mpctx)); #if ISC_MEMPOOL_NAMES if (mpctx->allocated > 0) UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_mempool_destroy(): mempool %s " + "isc__mempool_destroy(): mempool %s " "leaked memory", mpctx->name); #endif @@ -1734,9 +1944,10 @@ isc_mempool_destroy(isc_mempool_t **mpctxp) { mctx->poolcnt--; MCTXUNLOCK(mctx, &mctx->lock); - mpctx->magic = 0; + mpctx->common.impmagic = 0; + mpctx->common.magic = 0; - isc_mem_put(mpctx->mctx, mpctx, sizeof(isc_mempool_t)); + isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t)); if (lock != NULL) UNLOCK(lock); @@ -1744,8 +1955,10 @@ isc_mempool_destroy(isc_mempool_t **mpctxp) { *mpctxp = NULL; } -void -isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) { +ISC_MEMFUNC_SCOPE void +isc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + REQUIRE(VALID_MEMPOOL(mpctx)); REQUIRE(mpctx->lock == NULL); REQUIRE(lock != NULL); @@ -1753,10 +1966,11 @@ isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) { mpctx->lock = lock; } -void * -isc__mempool_get(isc_mempool_t *mpctx FLARG) { +ISC_MEMFUNC_SCOPE void * +isc___mempool_get(isc_mempool_t *mpctx0 FLARG) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; element *item; - isc_mem_t *mctx; + isc__mem_t *mctx; unsigned int i; REQUIRE(VALID_MEMPOOL(mpctx)); @@ -1835,9 +2049,10 @@ isc__mempool_get(isc_mempool_t *mpctx FLARG) { return (item); } -void -isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) { - isc_mem_t *mctx; +ISC_MEMFUNC_SCOPE void +isc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + isc__mem_t *mctx; element *item; REQUIRE(VALID_MEMPOOL(mpctx)); @@ -1892,8 +2107,10 @@ isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) { * Quotas */ -void -isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) { +ISC_MEMFUNC_SCOPE void +isc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + REQUIRE(VALID_MEMPOOL(mpctx)); if (mpctx->lock != NULL) @@ -1905,8 +2122,9 @@ isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) { UNLOCK(mpctx->lock); } -unsigned int -isc_mempool_getfreemax(isc_mempool_t *mpctx) { +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getfreemax(isc_mempool_t *mpctx0) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; unsigned int freemax; REQUIRE(VALID_MEMPOOL(mpctx)); @@ -1922,8 +2140,9 @@ isc_mempool_getfreemax(isc_mempool_t *mpctx) { return (freemax); } -unsigned int -isc_mempool_getfreecount(isc_mempool_t *mpctx) { +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getfreecount(isc_mempool_t *mpctx0) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; unsigned int freecount; REQUIRE(VALID_MEMPOOL(mpctx)); @@ -1939,8 +2158,10 @@ isc_mempool_getfreecount(isc_mempool_t *mpctx) { return (freecount); } -void -isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) { +ISC_MEMFUNC_SCOPE void +isc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + REQUIRE(limit > 0); REQUIRE(VALID_MEMPOOL(mpctx)); @@ -1954,8 +2175,9 @@ isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) { UNLOCK(mpctx->lock); } -unsigned int -isc_mempool_getmaxalloc(isc_mempool_t *mpctx) { +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getmaxalloc(isc_mempool_t *mpctx0) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; unsigned int maxalloc; REQUIRE(VALID_MEMPOOL(mpctx)); @@ -1971,8 +2193,9 @@ isc_mempool_getmaxalloc(isc_mempool_t *mpctx) { return (maxalloc); } -unsigned int -isc_mempool_getallocated(isc_mempool_t *mpctx) { +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getallocated(isc_mempool_t *mpctx0) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; unsigned int allocated; REQUIRE(VALID_MEMPOOL(mpctx)); @@ -1988,8 +2211,10 @@ isc_mempool_getallocated(isc_mempool_t *mpctx) { return (allocated); } -void -isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) { +ISC_MEMFUNC_SCOPE void +isc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + REQUIRE(limit > 0); REQUIRE(VALID_MEMPOOL(mpctx)); @@ -2002,8 +2227,10 @@ isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) { UNLOCK(mpctx->lock); } -unsigned int -isc_mempool_getfillcount(isc_mempool_t *mpctx) { +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getfillcount(isc_mempool_t *mpctx0) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + unsigned int fillcount; REQUIRE(VALID_MEMPOOL(mpctx)); @@ -2019,8 +2246,17 @@ isc_mempool_getfillcount(isc_mempool_t *mpctx) { return (fillcount); } -void -isc_mem_printactive(isc_mem_t *ctx, FILE *file) { +#ifdef USE_MEMIMPREGISTER +isc_result_t +isc__mem_register() { + return (isc_mem_register(isc__mem_create2)); +} +#endif + +#ifdef BIND9 +ISC_MEMFUNC_SCOPE void +isc__mem_printactive(isc_mem_t *ctx0, FILE *file) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; REQUIRE(VALID_CONTEXT(ctx)); REQUIRE(file != NULL); @@ -2033,12 +2269,12 @@ isc_mem_printactive(isc_mem_t *ctx, FILE *file) { #endif } -void -isc_mem_printallactive(FILE *file) { +ISC_MEMFUNC_SCOPE void +isc__mem_printallactive(FILE *file) { #if !ISC_MEM_TRACKLINES UNUSED(file); #else - isc_mem_t *ctx; + isc__mem_t *ctx; RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); @@ -2053,15 +2289,15 @@ isc_mem_printallactive(FILE *file) { #endif } -void -isc_mem_checkdestroyed(FILE *file) { +ISC_MEMFUNC_SCOPE void +isc__mem_checkdestroyed(FILE *file) { RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); LOCK(&lock); if (!ISC_LIST_EMPTY(contexts)) { #if ISC_MEM_TRACKLINES - isc_mem_t *ctx; + isc__mem_t *ctx; for (ctx = ISC_LIST_HEAD(contexts); ctx != NULL; @@ -2076,9 +2312,11 @@ isc_mem_checkdestroyed(FILE *file) { UNLOCK(&lock); } -unsigned int -isc_mem_references(isc_mem_t *ctx) { +ISC_MEMFUNC_SCOPE unsigned int +isc_mem_references(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; unsigned int references; + REQUIRE(VALID_CONTEXT(ctx)); MCTXLOCK(ctx, &ctx->lock); @@ -2098,7 +2336,7 @@ typedef struct summarystat { } summarystat_t; static void -renderctx(isc_mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) { +renderctx(isc__mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) { REQUIRE(VALID_CONTEXT(ctx)); xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"); @@ -2184,7 +2422,7 @@ renderctx(isc_mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) { void isc_mem_renderxml(xmlTextWriterPtr writer) { - isc_mem_t *ctx; + isc__mem_t *ctx; summarystat_t summary; isc_uint64_t lost; @@ -2236,3 +2474,4 @@ isc_mem_renderxml(xmlTextWriterPtr writer) { } #endif /* HAVE_LIBXML2 */ +#endif /* BIND9 */ diff --git a/lib/isc/mem_api.c b/lib/isc/mem_api.c new file mode 100644 index 0000000..638efcd --- /dev/null +++ b/lib/isc/mem_api.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: mem_api.c,v 1.8 2010-08-12 21:30:26 jinmei Exp $ */ + +#include + +#include +#include +#include +#include + +#if ISC_MEM_TRACKLINES +#define FLARG_PASS , file, line +#define FLARG , const char *file, unsigned int line +#else +#define FLARG_PASS +#define FLARG +#endif + +static isc_mutex_t createlock; +static isc_once_t once = ISC_ONCE_INIT; +static isc_memcreatefunc_t mem_createfunc = NULL; + +static void +initialize(void) { + RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS); +} + +isc_result_t +isc_mem_register(isc_memcreatefunc_t createfunc) { + isc_result_t result = ISC_R_SUCCESS; + + RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); + + LOCK(&createlock); + if (mem_createfunc == NULL) + mem_createfunc = createfunc; + else + result = ISC_R_EXISTS; + UNLOCK(&createlock); + + return (result); +} + +isc_result_t +isc_mem_create(size_t init_max_size, size_t target_size, isc_mem_t **mctxp) { + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(mem_createfunc != NULL); + result = (*mem_createfunc)(init_max_size, target_size, mctxp, + ISC_MEMFLAG_DEFAULT); + + UNLOCK(&createlock); + + return (result); +} + +isc_result_t +isc_mem_create2(size_t init_max_size, size_t target_size, isc_mem_t **mctxp, + unsigned int flags) +{ + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(mem_createfunc != NULL); + result = (*mem_createfunc)(init_max_size, target_size, mctxp, flags); + + UNLOCK(&createlock); + + return (result); +} + +void +isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) { + REQUIRE(ISCAPI_MCTX_VALID(source)); + REQUIRE(targetp != NULL && *targetp == NULL); + + source->methods->attach(source, targetp); + + ENSURE(*targetp == source); +} + +void +isc_mem_detach(isc_mem_t **mctxp) { + REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp)); + + (*mctxp)->methods->detach(mctxp); + + ENSURE(*mctxp == NULL); +} + +void +isc_mem_destroy(isc_mem_t **mctxp) { + REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp)); + + (*mctxp)->methods->destroy(mctxp); + + ENSURE(*mctxp == NULL); +} + +void * +isc__mem_get(isc_mem_t *mctx, size_t size FLARG) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->memget(mctx, size FLARG_PASS)); +} + +void +isc__mem_put(isc_mem_t *mctx, void *ptr, size_t size FLARG) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + mctx->methods->memput(mctx, ptr, size FLARG_PASS); +} + +void +isc__mem_putanddetach(isc_mem_t **mctxp, void *ptr, size_t size FLARG) { + REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp)); + + (*mctxp)->methods->memputanddetach(mctxp, ptr, size FLARG_PASS); + + /* + * XXX: We cannot always ensure *mctxp == NULL here + * (see lib/isc/mem.c). + */ +} + +void * +isc__mem_allocate(isc_mem_t *mctx, size_t size FLARG) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->memallocate(mctx, size FLARG_PASS)); +} + +void * +isc__mem_reallocate(isc_mem_t *mctx, void *ptr, size_t size FLARG) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->memreallocate(mctx, ptr, size FLARG_PASS)); +} + +char * +isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->memstrdup(mctx, s FLARG_PASS)); +} + +void +isc__mem_free(isc_mem_t *mctx, void *ptr FLARG) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + mctx->methods->memfree(mctx, ptr FLARG_PASS); +} + +void +isc_mem_setdestroycheck(isc_mem_t *mctx, isc_boolean_t flag) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + mctx->methods->setdestroycheck(mctx, flag); +} + +void +isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg, + size_t hiwater, size_t lowater) +{ + REQUIRE(ISCAPI_MCTX_VALID(ctx)); + + ctx->methods->setwater(ctx, water, water_arg, hiwater, lowater); +} + +void +isc_mem_waterack(isc_mem_t *ctx, int flag) { + REQUIRE(ISCAPI_MCTX_VALID(ctx)); + + ctx->methods->waterack(ctx, flag); +} + +size_t +isc_mem_inuse(isc_mem_t *mctx) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->inuse(mctx)); +} + +isc_boolean_t +isc_mem_isovermem(isc_mem_t *mctx) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->isovermem(mctx)); +} + +void +isc_mem_setname(isc_mem_t *mctx, const char *name, void *tag) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + UNUSED(name); + UNUSED(tag); + + return; +} + +const char * +isc_mem_getname(isc_mem_t *mctx) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (""); +} + +void * +isc_mem_gettag(isc_mem_t *mctx) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (NULL); +} + +isc_result_t +isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->mpcreate(mctx, size, mpctxp)); +} + +void +isc_mempool_destroy(isc_mempool_t **mpctxp) { + REQUIRE(mpctxp != NULL && ISCAPI_MPOOL_VALID(*mpctxp)); + + (*mpctxp)->methods->destroy(mpctxp); + + ENSURE(*mpctxp == NULL); +} + +void * +isc__mempool_get(isc_mempool_t *mpctx FLARG) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + return (mpctx->methods->get(mpctx FLARG_PASS)); +} + +void +isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + mpctx->methods->put(mpctx, mem FLARG_PASS); +} + +unsigned int +isc_mempool_getallocated(isc_mempool_t *mpctx) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + return (mpctx->methods->getallocated(mpctx)); +} + +void +isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + mpctx->methods->setmaxalloc(mpctx, limit); +} + +void +isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + mpctx->methods->setfreemax(mpctx, limit); +} + +void +isc_mempool_setname(isc_mempool_t *mpctx, const char *name) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + mpctx->methods->setname(mpctx, name); +} + +void +isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + mpctx->methods->associatelock(mpctx, lock); +} + +void +isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + mpctx->methods->setfillcount(mpctx, limit); +} diff --git a/lib/isc/netaddr.c b/lib/isc/netaddr.c index 92c4fe5..33dddb8 100644 --- a/lib/isc/netaddr.c +++ b/lib/isc/netaddr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: netaddr.c,v 1.38 2007-06-18 23:47:44 tbox Exp $ */ +/* $Id: netaddr.c,v 1.41 2010-11-17 23:47:08 tbox Exp $ */ /*! \file */ @@ -303,18 +303,18 @@ isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) { isc_result_t isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) { #ifdef ISC_PLATFORM_HAVESYSUNH - if (strlen(path) > sizeof(netaddr->type.un) - 1) - return (ISC_R_NOSPACE); - - memset(netaddr, 0, sizeof(*netaddr)); - netaddr->family = AF_UNIX; - strcpy(netaddr->type.un, path); - netaddr->zone = 0; - return (ISC_R_SUCCESS); -#else + if (strlen(path) > sizeof(netaddr->type.un) - 1) + return (ISC_R_NOSPACE); + + memset(netaddr, 0, sizeof(*netaddr)); + netaddr->family = AF_UNIX; + strcpy(netaddr->type.un, path); + netaddr->zone = 0; + return (ISC_R_SUCCESS); +#else UNUSED(netaddr); UNUSED(path); - return (ISC_R_NOTIMPLEMENTED); + return (ISC_R_NOTIMPLEMENTED); #endif } diff --git a/lib/isc/nls/Makefile.in b/lib/isc/nls/Makefile.in index c4ec7a1..bfd8dd0 100644 --- a/lib/isc/nls/Makefile.in +++ b/lib/isc/nls/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 1999-2001 Internet Software Consortium. # # Permission to use, copy, modify, and/or distribute this software for any @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.14 2007-06-19 23:47:18 tbox Exp $ +# $Id: Makefile.in,v 1.17 2009-12-05 23:31:41 each Exp $ srcdir = @srcdir@ VPATH = @srcdir@ diff --git a/lib/isc/nothreads/Makefile.in b/lib/isc/nothreads/Makefile.in index 042cfce..29bacd6 100644 --- a/lib/isc/nothreads/Makefile.in +++ b/lib/isc/nothreads/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2004, 2007, 2010 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004, 2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 2000, 2001 Internet Software Consortium. # # Permission to use, copy, modify, and/or distribute this software for any @@ -13,11 +13,11 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.7.332.2 2010-06-09 23:48:16 tbox Exp $ +# $Id: Makefile.in,v 1.12 2010-06-09 23:50:58 tbox Exp $ -srcdir = @srcdir@ -VPATH = @srcdir@ top_srcdir = @top_srcdir@ +srcdir = @top_srcdir@/lib/isc/nothreads +VPATH = @top_srcdir@/lib/isc/nothreads CINCLUDES = -I${srcdir}/include \ -I${srcdir}/../unix/include \ diff --git a/lib/isc/powerpc/include/isc/atomic.h b/lib/isc/powerpc/include/isc/atomic.h index 074fea1..2e11e39 100644 --- a/lib/isc/powerpc/include/isc/atomic.h +++ b/lib/isc/powerpc/include/isc/atomic.h @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: atomic.h,v 1.6.332.2 2009-10-14 23:47:14 tbox Exp $ */ +/* $Id: atomic.h,v 1.8 2009-10-14 23:47:51 tbox Exp $ */ #ifndef ISC_ATOMIC_H #define ISC_ATOMIC_H 1 diff --git a/lib/isc/print.c b/lib/isc/print.c index 5d800f3..bd7b580 100644 --- a/lib/isc/print.c +++ b/lib/isc/print.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: print.c,v 1.35.130.2 2010-10-18 23:46:17 tbox Exp $ */ +/* $Id: print.c,v 1.37 2010-10-18 23:47:08 tbox Exp $ */ /*! \file */ diff --git a/lib/isc/pthreads/Makefile.in b/lib/isc/pthreads/Makefile.in index 572d76c..7aae93d 100644 --- a/lib/isc/pthreads/Makefile.in +++ b/lib/isc/pthreads/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 1998-2001 Internet Software Consortium. # # Permission to use, copy, modify, and/or distribute this software for any @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.19 2007-06-19 23:47:18 tbox Exp $ +# $Id: Makefile.in,v 1.22 2009-12-05 23:31:41 each Exp $ srcdir = @srcdir@ VPATH = @srcdir@ diff --git a/lib/isc/pthreads/mutex.c b/lib/isc/pthreads/mutex.c index efe38db..fa5a701 100644 --- a/lib/isc/pthreads/mutex.c +++ b/lib/isc/pthreads/mutex.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mutex.c,v 1.16.112.2 2011-01-04 23:45:43 tbox Exp $ */ +/* $Id: mutex.c,v 1.18 2011-01-04 23:47:14 tbox Exp $ */ /*! \file */ diff --git a/lib/isc/radix.c b/lib/isc/radix.c index d72ed33..be2e841 100644 --- a/lib/isc/radix.c +++ b/lib/isc/radix.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: radix.c,v 1.20.36.3 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: radix.c,v 1.23 2009-01-18 23:48:14 tbox Exp $ */ /* * This source was adapted from MRT's RCS Ids: diff --git a/lib/isc/random.c b/lib/isc/random.c index 09145f4..f082fe6 100644 --- a/lib/isc/random.c +++ b/lib/isc/random.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: random.c,v 1.25.332.2 2009-07-16 23:47:17 tbox Exp $ */ +/* $Id: random.c,v 1.28 2009-07-16 05:52:46 marka Exp $ */ /*! \file */ @@ -103,7 +103,7 @@ isc_uint32_t isc_random_jitter(isc_uint32_t max, isc_uint32_t jitter) { isc_uint32_t rnd; - REQUIRE(jitter < max); + REQUIRE(jitter < max || (jitter == 0 && max == 0)); if (jitter == 0) return (max); diff --git a/lib/isc/rwlock.c b/lib/isc/rwlock.c index 39b90d7..fce7516 100644 --- a/lib/isc/rwlock.c +++ b/lib/isc/rwlock.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rwlock.c,v 1.44.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: rwlock.c,v 1.46 2009-01-18 23:48:14 tbox Exp $ */ /*! \file */ diff --git a/lib/isc/sha1.c b/lib/isc/sha1.c index 20ee28d..d72eb9c 100644 --- a/lib/isc/sha1.c +++ b/lib/isc/sha1.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sha1.c,v 1.18 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: sha1.c,v 1.20 2009-02-06 23:47:42 tbox Exp $ */ /* $NetBSD: sha1.c,v 1.5 2000/01/22 22:19:14 mycroft Exp $ */ /* $OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $ */ @@ -38,11 +38,47 @@ #include "config.h" #include +#include #include #include #include #include +#ifdef ISC_PLATFORM_OPENSSLHASH + +void +isc_sha1_init(isc_sha1_t *context) +{ + INSIST(context != NULL); + + EVP_DigestInit(context, EVP_sha1()); +} + +void +isc_sha1_invalidate(isc_sha1_t *context) { + EVP_MD_CTX_cleanup(context); +} + +void +isc_sha1_update(isc_sha1_t *context, const unsigned char *data, + unsigned int len) +{ + INSIST(context != 0); + INSIST(data != 0); + + EVP_DigestUpdate(context, (const void *) data, (size_t) len); +} + +void +isc_sha1_final(isc_sha1_t *context, unsigned char *digest) { + INSIST(digest != 0); + INSIST(context != 0); + + EVP_DigestFinal(context, digest, NULL); +} + +#else + #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /*@{*/ @@ -313,3 +349,4 @@ isc_sha1_final(isc_sha1_t *context, unsigned char *digest) { memset(context, 0, sizeof(isc_sha1_t)); } +#endif diff --git a/lib/isc/sha2.c b/lib/isc/sha2.c index 22f1d47..1dc05a70 100644 --- a/lib/isc/sha2.c +++ b/lib/isc/sha2.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2005-2007, 2009 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sha2.c,v 1.13.332.4 2010-01-15 23:47:34 tbox Exp $ */ +/* $Id: sha2.c,v 1.18 2009-10-22 02:21:31 each Exp $ */ /* $FreeBSD$ */ /* $KAME: sha2.c,v 1.8 2001/11/08 01:07:52 itojun Exp $ */ @@ -58,10 +58,169 @@ #include #include +#include #include #include #include +#ifdef ISC_PLATFORM_OPENSSLHASH + +void +isc_sha224_init(isc_sha224_t *context) { + if (context == (isc_sha224_t *)0) { + return; + } + EVP_DigestInit(context, EVP_sha224()); +} + +void +isc_sha224_invalidate(isc_sha224_t *context) { + EVP_MD_CTX_cleanup(context); +} + +void +isc_sha224_update(isc_sha224_t *context, const isc_uint8_t* data, size_t len) { + if (len == 0U) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + REQUIRE(context != (isc_sha224_t *)0 && data != (isc_uint8_t*)0); + + EVP_DigestUpdate(context, (const void *) data, len); +} + +void +isc_sha224_final(isc_uint8_t digest[], isc_sha224_t *context) { + /* Sanity check: */ + REQUIRE(context != (isc_sha224_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + EVP_DigestFinal(context, digest, NULL); + } else { + EVP_MD_CTX_cleanup(context); + } +} + +void +isc_sha256_init(isc_sha256_t *context) { + if (context == (isc_sha256_t *)0) { + return; + } + EVP_DigestInit(context, EVP_sha256()); +} + +void +isc_sha256_invalidate(isc_sha256_t *context) { + EVP_MD_CTX_cleanup(context); +} + +void +isc_sha256_update(isc_sha256_t *context, const isc_uint8_t *data, size_t len) { + if (len == 0U) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + REQUIRE(context != (isc_sha256_t *)0 && data != (isc_uint8_t*)0); + + EVP_DigestUpdate(context, (const void *) data, len); +} + +void +isc_sha256_final(isc_uint8_t digest[], isc_sha256_t *context) { + /* Sanity check: */ + REQUIRE(context != (isc_sha256_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + EVP_DigestFinal(context, digest, NULL); + } else { + EVP_MD_CTX_cleanup(context); + } +} + +void +isc_sha512_init(isc_sha512_t *context) { + if (context == (isc_sha512_t *)0) { + return; + } + EVP_DigestInit(context, EVP_sha512()); +} + +void +isc_sha512_invalidate(isc_sha512_t *context) { + EVP_MD_CTX_cleanup(context); +} + +void isc_sha512_update(isc_sha512_t *context, const isc_uint8_t *data, size_t len) { + if (len == 0U) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + REQUIRE(context != (isc_sha512_t *)0 && data != (isc_uint8_t*)0); + + EVP_DigestUpdate(context, (const void *) data, len); +} + +void isc_sha512_final(isc_uint8_t digest[], isc_sha512_t *context) { + /* Sanity check: */ + REQUIRE(context != (isc_sha512_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + EVP_DigestFinal(context, digest, NULL); + } else { + EVP_MD_CTX_cleanup(context); + } +} + +void +isc_sha384_init(isc_sha384_t *context) { + if (context == (isc_sha384_t *)0) { + return; + } + EVP_DigestInit(context, EVP_sha384()); +} + +void +isc_sha384_invalidate(isc_sha384_t *context) { + EVP_MD_CTX_cleanup(context); +} + +void +isc_sha384_update(isc_sha384_t *context, const isc_uint8_t* data, size_t len) { + if (len == 0U) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + REQUIRE(context != (isc_sha512_t *)0 && data != (isc_uint8_t*)0); + + EVP_DigestUpdate(context, (const void *) data, len); +} + +void +isc_sha384_final(isc_uint8_t digest[], isc_sha384_t *context) { + /* Sanity check: */ + REQUIRE(context != (isc_sha384_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + EVP_DigestFinal(context, digest, NULL); + } else { + EVP_MD_CTX_cleanup(context); + } +} + +#else + /* * UNROLLED TRANSFORM LOOP NOTE: * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform @@ -394,13 +553,6 @@ static const isc_uint64_t sha512_initial_hash_value[8] = { }; #endif -/* - * Constant used by SHA256/384/512_End() functions for converting the - * digest to a readable hexadecimal character string: - */ -static const char *sha2_hex_digits = "0123456789abcdef"; - - /*** SHA-224: *********************************************************/ void @@ -432,41 +584,6 @@ isc_sha224_final(isc_uint8_t digest[], isc_sha224_t *context) { memset(sha256_digest, 0, ISC_SHA256_DIGESTLENGTH); } -char * -isc_sha224_end(isc_sha224_t *context, char buffer[]) { - isc_uint8_t digest[ISC_SHA224_DIGESTLENGTH], *d = digest; - unsigned int i; - - /* Sanity check: */ - REQUIRE(context != (isc_sha224_t *)0); - - if (buffer != (char*)0) { - isc_sha224_final(digest, context); - - for (i = 0; i < ISC_SHA224_DIGESTLENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - memset(context, 0, sizeof(context)); - } - memset(digest, 0, ISC_SHA224_DIGESTLENGTH); - return buffer; -} - -char* -isc_sha224_data(const isc_uint8_t *data, size_t len, - char digest[ISC_SHA224_DIGESTSTRINGLENGTH]) -{ - isc_sha224_t context; - - isc_sha224_init(&context); - isc_sha224_update(&context, data, len); - return (isc_sha224_end(&context, digest)); -} - /*** SHA-256: *********************************************************/ void isc_sha256_init(isc_sha256_t *context) { @@ -479,6 +596,11 @@ isc_sha256_init(isc_sha256_t *context) { context->bitcount = 0; } +void +isc_sha256_invalidate(isc_sha256_t *context) { + memset(context, 0, sizeof(isc_sha256_t)); +} + #ifdef ISC_SHA2_UNROLL_TRANSFORM /* Unrolled SHA-256 round macros: */ @@ -656,11 +778,6 @@ isc_sha256_transform(isc_sha256_t *context, const isc_uint32_t* data) { #endif /* ISC_SHA2_UNROLL_TRANSFORM */ void -isc_sha256_invalidate(isc_sha256_t *context) { - memset(context, 0, sizeof(isc_sha256_t)); -} - -void isc_sha256_update(isc_sha256_t *context, const isc_uint8_t *data, size_t len) { unsigned int freespace, usedspace; @@ -782,42 +899,6 @@ isc_sha256_final(isc_uint8_t digest[], isc_sha256_t *context) { usedspace = 0; } -char * -isc_sha256_end(isc_sha256_t *context, char buffer[]) { - isc_uint8_t digest[ISC_SHA256_DIGESTLENGTH], *d = digest; - unsigned int i; - - /* Sanity check: */ - REQUIRE(context != (isc_sha256_t *)0); - - if (buffer != (char*)0) { - isc_sha256_final(digest, context); - - for (i = 0; i < ISC_SHA256_DIGESTLENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - memset(context, 0, sizeof(context)); - } - memset(digest, 0, ISC_SHA256_DIGESTLENGTH); - return buffer; -} - -char * -isc_sha256_data(const isc_uint8_t* data, size_t len, - char digest[ISC_SHA256_DIGESTSTRINGLENGTH]) -{ - isc_sha256_t context; - - isc_sha256_init(&context); - isc_sha256_update(&context, data, len); - return (isc_sha256_end(&context, digest)); -} - - /*** SHA-512: *********************************************************/ void isc_sha512_init(isc_sha512_t *context) { @@ -830,6 +911,11 @@ isc_sha512_init(isc_sha512_t *context) { context->bitcount[0] = context->bitcount[1] = 0; } +void +isc_sha512_invalidate(isc_sha512_t *context) { + memset(context, 0, sizeof(isc_sha512_t)); +} + #ifdef ISC_SHA2_UNROLL_TRANSFORM /* Unrolled SHA-512 round macros: */ @@ -1000,13 +1086,7 @@ isc_sha512_transform(isc_sha512_t *context, const isc_uint64_t* data) { #endif /* ISC_SHA2_UNROLL_TRANSFORM */ -void -isc_sha512_invalidate(isc_sha512_t *context) { - memset(context, 0, sizeof(isc_sha512_t)); -} - -void -isc_sha512_update(isc_sha512_t *context, const isc_uint8_t *data, size_t len) { +void isc_sha512_update(isc_sha512_t *context, const isc_uint8_t *data, size_t len) { unsigned int freespace, usedspace; if (len == 0U) { @@ -1131,41 +1211,6 @@ void isc_sha512_final(isc_uint8_t digest[], isc_sha512_t *context) { memset(context, 0, sizeof(context)); } -char * -isc_sha512_end(isc_sha512_t *context, char buffer[]) { - isc_uint8_t digest[ISC_SHA512_DIGESTLENGTH], *d = digest; - unsigned int i; - - /* Sanity check: */ - REQUIRE(context != (isc_sha512_t *)0); - - if (buffer != (char*)0) { - isc_sha512_final(digest, context); - - for (i = 0; i < ISC_SHA512_DIGESTLENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - memset(context, 0, sizeof(context)); - } - memset(digest, 0, ISC_SHA512_DIGESTLENGTH); - return buffer; -} - -char * -isc_sha512_data(const isc_uint8_t *data, size_t len, - char digest[ISC_SHA512_DIGESTSTRINGLENGTH]) -{ - isc_sha512_t context; - - isc_sha512_init(&context); - isc_sha512_update(&context, data, len); - return (isc_sha512_end(&context, digest)); -} - /*** SHA-384: *********************************************************/ void @@ -1218,6 +1263,130 @@ isc_sha384_final(isc_uint8_t digest[], isc_sha384_t *context) { /* Zero out state data */ memset(context, 0, sizeof(context)); } +#endif /* !ISC_PLATFORM_OPENSSLHASH */ + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + +char * +isc_sha224_end(isc_sha224_t *context, char buffer[]) { + isc_uint8_t digest[ISC_SHA224_DIGESTLENGTH], *d = digest; + unsigned int i; + + /* Sanity check: */ + REQUIRE(context != (isc_sha224_t *)0); + + if (buffer != (char*)0) { + isc_sha224_final(digest, context); + + for (i = 0; i < ISC_SHA224_DIGESTLENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { +#ifdef ISC_PLATFORM_OPENSSLHASH + EVP_MD_CTX_cleanup(context); +#else + memset(context, 0, sizeof(context)); +#endif + } + memset(digest, 0, ISC_SHA224_DIGESTLENGTH); + return buffer; +} + +char * +isc_sha224_data(const isc_uint8_t *data, size_t len, + char digest[ISC_SHA224_DIGESTSTRINGLENGTH]) +{ + isc_sha224_t context; + + isc_sha224_init(&context); + isc_sha224_update(&context, data, len); + return (isc_sha224_end(&context, digest)); +} + +char * +isc_sha256_end(isc_sha256_t *context, char buffer[]) { + isc_uint8_t digest[ISC_SHA256_DIGESTLENGTH], *d = digest; + unsigned int i; + + /* Sanity check: */ + REQUIRE(context != (isc_sha256_t *)0); + + if (buffer != (char*)0) { + isc_sha256_final(digest, context); + + for (i = 0; i < ISC_SHA256_DIGESTLENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { +#ifdef ISC_PLATFORM_OPENSSLHASH + EVP_MD_CTX_cleanup(context); +#else + memset(context, 0, sizeof(context)); +#endif + } + memset(digest, 0, ISC_SHA256_DIGESTLENGTH); + return buffer; +} + +char * +isc_sha256_data(const isc_uint8_t* data, size_t len, + char digest[ISC_SHA256_DIGESTSTRINGLENGTH]) +{ + isc_sha256_t context; + + isc_sha256_init(&context); + isc_sha256_update(&context, data, len); + return (isc_sha256_end(&context, digest)); +} + +char * +isc_sha512_end(isc_sha512_t *context, char buffer[]) { + isc_uint8_t digest[ISC_SHA512_DIGESTLENGTH], *d = digest; + unsigned int i; + + /* Sanity check: */ + REQUIRE(context != (isc_sha512_t *)0); + + if (buffer != (char*)0) { + isc_sha512_final(digest, context); + + for (i = 0; i < ISC_SHA512_DIGESTLENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { +#ifdef ISC_PLATFORM_OPENSSLHASH + EVP_MD_CTX_cleanup(context); +#else + memset(context, 0, sizeof(context)); +#endif + } + memset(digest, 0, ISC_SHA512_DIGESTLENGTH); + return buffer; +} + +char * +isc_sha512_data(const isc_uint8_t *data, size_t len, + char digest[ISC_SHA512_DIGESTSTRINGLENGTH]) +{ + isc_sha512_t context; + + isc_sha512_init(&context); + isc_sha512_update(&context, data, len); + return (isc_sha512_end(&context, digest)); +} char * isc_sha384_end(isc_sha384_t *context, char buffer[]) { @@ -1237,13 +1406,17 @@ isc_sha384_end(isc_sha384_t *context, char buffer[]) { } *buffer = (char)0; } else { +#ifdef ISC_PLATFORM_OPENSSLHASH + EVP_MD_CTX_cleanup(context); +#else memset(context, 0, sizeof(context)); +#endif } memset(digest, 0, ISC_SHA384_DIGESTLENGTH); return buffer; } -char* +char * isc_sha384_data(const isc_uint8_t *data, size_t len, char digest[ISC_SHA384_DIGESTSTRINGLENGTH]) { diff --git a/lib/isc/sockaddr.c b/lib/isc/sockaddr.c index 19833e4..9661ee4 100644 --- a/lib/isc/sockaddr.c +++ b/lib/isc/sockaddr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sockaddr.c,v 1.70 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: sockaddr.c,v 1.73 2010-11-17 23:47:09 tbox Exp $ */ /*! \file */ @@ -390,8 +390,8 @@ isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na, #endif sockaddr->type.sin6.sin6_port = htons(port); break; - default: - INSIST(0); + default: + INSIST(0); } ISC_LINK_INIT(sockaddr, link); } diff --git a/lib/isc/socket_api.c b/lib/isc/socket_api.c new file mode 100644 index 0000000..c1e5fd4 --- /dev/null +++ b/lib/isc/socket_api.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: socket_api.c,v 1.5 2009-10-01 01:30:01 sar Exp $ */ + +#include + +#include +#include +#include +#include +#include +#include + +static isc_mutex_t createlock; +static isc_once_t once = ISC_ONCE_INIT; +static isc_socketmgrcreatefunc_t socketmgr_createfunc = NULL; + +static void +initialize(void) { + RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS); +} + +isc_result_t +isc_socket_register(isc_socketmgrcreatefunc_t createfunc) { + isc_result_t result = ISC_R_SUCCESS; + + RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); + + LOCK(&createlock); + if (socketmgr_createfunc == NULL) + socketmgr_createfunc = createfunc; + else + result = ISC_R_EXISTS; + UNLOCK(&createlock); + + return (result); +} + +isc_result_t +isc_socketmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, + isc_socketmgr_t **managerp) +{ + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(socketmgr_createfunc != NULL); + result = (*socketmgr_createfunc)(mctx, managerp); + + UNLOCK(&createlock); + + if (result == ISC_R_SUCCESS) + isc_appctx_setsocketmgr(actx, *managerp); + + return (result); +} + +isc_result_t +isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) { + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(socketmgr_createfunc != NULL); + result = (*socketmgr_createfunc)(mctx, managerp); + + UNLOCK(&createlock); + + return (result); +} + +void +isc_socketmgr_destroy(isc_socketmgr_t **managerp) { + REQUIRE(managerp != NULL && ISCAPI_SOCKETMGR_VALID(*managerp)); + + (*managerp)->methods->destroy(managerp); + + ENSURE(*managerp == NULL); +} + +isc_result_t +isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, + isc_socket_t **socketp) +{ + REQUIRE(ISCAPI_SOCKETMGR_VALID(manager)); + + return (manager->methods->socketcreate(manager, pf, type, socketp)); +} + +void +isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) { + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + REQUIRE(socketp != NULL && *socketp == NULL); + + sock->methods->attach(sock, socketp); + + ENSURE(*socketp == sock); +} + +void +isc_socket_detach(isc_socket_t **socketp) { + REQUIRE(socketp != NULL && ISCAPI_SOCKET_VALID(*socketp)); + + (*socketp)->methods->detach(socketp); + + ENSURE(*socketp == NULL); +} + +isc_result_t +isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr, + unsigned int options) +{ + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return (sock->methods->bind(sock, sockaddr, options)); +} + +isc_result_t +isc_socket_sendto(isc_socket_t *sock, isc_region_t *region, isc_task_t *task, + isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo) +{ + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return (sock->methods->sendto(sock, region, task, action, arg, address, + pktinfo)); +} + +isc_result_t +isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, isc_task_t *task, + isc_taskaction_t action, const void *arg) +{ + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return (sock->methods->connect(sock, addr, task, action, arg)); +} + +isc_result_t +isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum, + isc_task_t *task, isc_taskaction_t action, const void *arg) +{ + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return (sock->methods->recv(sock, region, minimum, task, action, arg)); +} + +void +isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) { + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + sock->methods->cancel(sock, task, how); +} + +isc_result_t +isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) { + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return (sock->methods->getsockname(sock, addressp)); +} + +void +isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) { + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + sock->methods->ipv6only(sock, yes); +} + +isc_sockettype_t +isc_socket_gettype(isc_socket_t *sock) { + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return (sock->methods->gettype(sock)); +} + +void +isc_socket_setname(isc_socket_t *socket, const char *name, void *tag) { + REQUIRE(ISCAPI_SOCKET_VALID(socket)); + + UNUSED(socket); /* in case REQUIRE() is empty */ + UNUSED(name); + UNUSED(tag); +} + +isc_result_t +isc_socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags, + isc_sockfdwatch_t callback, void *cbarg, + isc_task_t *task, isc_socket_t **socketp) +{ + REQUIRE(ISCAPI_SOCKETMGR_VALID(manager)); + + return (manager->methods->fdwatchcreate(manager, fd, flags, + callback, cbarg, task, + socketp)); +} + +isc_result_t +isc_socket_fdwatchpoke(isc_socket_t *sock, int flags) +{ + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return(sock->methods->fdwatchpoke(sock, flags)); +} diff --git a/lib/isc/stats.c b/lib/isc/stats.c index ac66bcf..e72fb54 100644 --- a/lib/isc/stats.c +++ b/lib/isc/stats.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: stats.c,v 1.3.6.2 2009-01-29 23:47:44 tbox Exp $ */ +/* $Id: stats.c,v 1.3 2009-01-27 23:47:54 tbox Exp $ */ /*! \file */ diff --git a/lib/isc/task.c b/lib/isc/task.c index 5d87f21..a9dfd1f 100644 --- a/lib/isc/task.c +++ b/lib/isc/task.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: task.c,v 1.107.120.2 2010-12-03 23:45:47 tbox Exp $ */ +/* $Id: task.c,v 1.115.14.1.2.1 2011-06-02 23:47:36 tbox Exp $ */ /*! \file * \author Principal Author: Bob Halley @@ -40,9 +40,33 @@ #include #include -#ifndef ISC_PLATFORM_USETHREADS +#ifdef OPENSSL_LEAKS +#include +#endif + +/*% + * For BIND9 internal applications: + * when built with threads we use multiple worker threads shared by the whole + * application. + * when built without threads we share a single global task manager and use + * an integrated event loop for socket, timer, and other generic task events. + * For generic library: + * we don't use either of them: an application can have multiple task managers + * whether or not it's threaded, and if the application is threaded each thread + * is expected to have a separate manager; no "worker threads" are shared by + * the application threads. + */ +#ifdef BIND9 +#ifdef ISC_PLATFORM_USETHREADS +#define USE_WORKER_THREADS +#else +#define USE_SHARED_MANAGER +#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* BIND9 */ + +#ifndef USE_WORKER_THREADS #include "task_p.h" -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WORKER_THREADS */ #ifdef ISC_TASK_TRACE #define XTRACE(m) fprintf(stderr, "task %p thread %lu: %s\n", \ @@ -66,7 +90,7 @@ typedef enum { task_state_done } task_state_t; -#ifdef HAVE_LIBXML2 +#if defined(HAVE_LIBXML2) && defined(BIND9) static const char *statenames[] = { "idle", "ready", "running", "done", }; @@ -75,10 +99,13 @@ static const char *statenames[] = { #define TASK_MAGIC ISC_MAGIC('T', 'A', 'S', 'K') #define VALID_TASK(t) ISC_MAGIC_VALID(t, TASK_MAGIC) -struct isc_task { +typedef struct isc__task isc__task_t; +typedef struct isc__taskmgr isc__taskmgr_t; + +struct isc__task { /* Not locked. */ - unsigned int magic; - isc_taskmgr_t * manager; + isc_task_t common; + isc__taskmgr_t * manager; isc_mutex_t lock; /* Locked by task lock. */ task_state_t state; @@ -91,8 +118,8 @@ struct isc_task { char name[16]; void * tag; /* Locked by task manager lock. */ - LINK(isc_task_t) link; - LINK(isc_task_t) ready_link; + LINK(isc__task_t) link; + LINK(isc__task_t) ready_link; }; #define TASK_F_SHUTTINGDOWN 0x01 @@ -103,9 +130,11 @@ struct isc_task { #define TASK_MANAGER_MAGIC ISC_MAGIC('T', 'S', 'K', 'M') #define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TASK_MANAGER_MAGIC) -struct isc_taskmgr { +typedef ISC_LIST(isc__task_t) isc__tasklist_t; + +struct isc__taskmgr { /* Not locked. */ - unsigned int magic; + isc_taskmgr_t common; isc_mem_t * mctx; isc_mutex_t lock; #ifdef ISC_PLATFORM_USETHREADS @@ -114,8 +143,8 @@ struct isc_taskmgr { #endif /* ISC_PLATFORM_USETHREADS */ /* Locked by task manager lock. */ unsigned int default_quantum; - LIST(isc_task_t) tasks; - isc_tasklist_t ready_tasks; + LIST(isc__task_t) tasks; + isc__tasklist_t ready_tasks; #ifdef ISC_PLATFORM_USETHREADS isc_condition_t work_available; isc_condition_t exclusive_granted; @@ -123,7 +152,7 @@ struct isc_taskmgr { unsigned int tasks_running; isc_boolean_t exclusive_requested; isc_boolean_t exiting; -#ifndef ISC_PLATFORM_USETHREADS +#ifdef USE_SHARED_MANAGER unsigned int refs; #endif /* ISC_PLATFORM_USETHREADS */ }; @@ -132,17 +161,116 @@ struct isc_taskmgr { #define DEFAULT_DEFAULT_QUANTUM 5 #define FINISHED(m) ((m)->exiting && EMPTY((m)->tasks)) -#ifndef ISC_PLATFORM_USETHREADS -static isc_taskmgr_t *taskmgr = NULL; -#endif /* ISC_PLATFORM_USETHREADS */ +#ifdef USE_SHARED_MANAGER +static isc__taskmgr_t *taskmgr = NULL; +#endif /* USE_SHARED_MANAGER */ + +/*% + * The following can be either static or public, depending on build environment. + */ + +#ifdef BIND9 +#define ISC_TASKFUNC_SCOPE +#else +#define ISC_TASKFUNC_SCOPE static +#endif + +ISC_TASKFUNC_SCOPE isc_result_t +isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum, + isc_task_t **taskp); +ISC_TASKFUNC_SCOPE void +isc__task_attach(isc_task_t *source0, isc_task_t **targetp); +ISC_TASKFUNC_SCOPE void +isc__task_detach(isc_task_t **taskp); +ISC_TASKFUNC_SCOPE void +isc__task_send(isc_task_t *task0, isc_event_t **eventp); +ISC_TASKFUNC_SCOPE void +isc__task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp); +ISC_TASKFUNC_SCOPE unsigned int +isc__task_purgerange(isc_task_t *task0, void *sender, isc_eventtype_t first, + isc_eventtype_t last, void *tag); +ISC_TASKFUNC_SCOPE unsigned int +isc__task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag); +ISC_TASKFUNC_SCOPE isc_boolean_t +isc__task_purgeevent(isc_task_t *task0, isc_event_t *event); +ISC_TASKFUNC_SCOPE unsigned int +isc__task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first, + isc_eventtype_t last, void *tag, + isc_eventlist_t *events); +ISC_TASKFUNC_SCOPE unsigned int +isc__task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag, isc_eventlist_t *events); +ISC_TASKFUNC_SCOPE isc_result_t +isc__task_onshutdown(isc_task_t *task0, isc_taskaction_t action, + const void *arg); +ISC_TASKFUNC_SCOPE void +isc__task_shutdown(isc_task_t *task0); +ISC_TASKFUNC_SCOPE void +isc__task_destroy(isc_task_t **taskp); +ISC_TASKFUNC_SCOPE void +isc__task_setname(isc_task_t *task0, const char *name, void *tag); +ISC_TASKFUNC_SCOPE const char * +isc__task_getname(isc_task_t *task0); +ISC_TASKFUNC_SCOPE void * +isc__task_gettag(isc_task_t *task0); +ISC_TASKFUNC_SCOPE void +isc__task_getcurrenttime(isc_task_t *task0, isc_stdtime_t *t); +ISC_TASKFUNC_SCOPE isc_result_t +isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers, + unsigned int default_quantum, isc_taskmgr_t **managerp); +ISC_TASKFUNC_SCOPE void +isc__taskmgr_destroy(isc_taskmgr_t **managerp); +ISC_TASKFUNC_SCOPE isc_result_t +isc__task_beginexclusive(isc_task_t *task); +ISC_TASKFUNC_SCOPE void +isc__task_endexclusive(isc_task_t *task0); + +static struct isc__taskmethods { + isc_taskmethods_t methods; + + /*% + * The following are defined just for avoiding unused static functions. + */ +#ifndef BIND9 + void *purgeevent, *unsendrange, *getname, *gettag, *getcurrenttime; +#endif +} taskmethods = { + { + isc__task_attach, + isc__task_detach, + isc__task_destroy, + isc__task_send, + isc__task_sendanddetach, + isc__task_unsend, + isc__task_onshutdown, + isc__task_shutdown, + isc__task_setname, + isc__task_purge, + isc__task_purgerange, + isc__task_beginexclusive, + isc__task_endexclusive + } +#ifndef BIND9 + , + (void *)isc__task_purgeevent, (void *)isc__task_unsendrange, + (void *)isc__task_getname, (void *)isc__task_gettag, + (void *)isc__task_getcurrenttime +#endif +}; + +static isc_taskmgrmethods_t taskmgrmethods = { + isc__taskmgr_destroy, + isc__task_create +}; /*** *** Tasks. ***/ static void -task_finished(isc_task_t *task) { - isc_taskmgr_t *manager = task->manager; +task_finished(isc__task_t *task) { + isc__taskmgr_t *manager = task->manager; REQUIRE(EMPTY(task->events)); REQUIRE(EMPTY(task->on_shutdown)); @@ -153,7 +281,7 @@ task_finished(isc_task_t *task) { LOCK(&manager->lock); UNLINK(manager->tasks, task, link); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WORKER_THREADS if (FINISHED(manager)) { /* * All tasks have completed and the @@ -163,19 +291,21 @@ task_finished(isc_task_t *task) { */ BROADCAST(&manager->work_available); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WORKER_THREADS */ UNLOCK(&manager->lock); DESTROYLOCK(&task->lock); - task->magic = 0; + task->common.impmagic = 0; + task->common.magic = 0; isc_mem_put(manager->mctx, task, sizeof(*task)); } -isc_result_t -isc_task_create(isc_taskmgr_t *manager, unsigned int quantum, - isc_task_t **taskp) +ISC_TASKFUNC_SCOPE isc_result_t +isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum, + isc_task_t **taskp) { - isc_task_t *task; + isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; + isc__task_t *task; isc_boolean_t exiting; isc_result_t result; @@ -220,14 +350,17 @@ isc_task_create(isc_taskmgr_t *manager, unsigned int quantum, return (ISC_R_SHUTTINGDOWN); } - task->magic = TASK_MAGIC; - *taskp = task; + task->common.methods = (isc_taskmethods_t *)&taskmethods; + task->common.magic = ISCAPI_TASK_MAGIC; + task->common.impmagic = TASK_MAGIC; + *taskp = (isc_task_t *)task; return (ISC_R_SUCCESS); } -void -isc_task_attach(isc_task_t *source, isc_task_t **targetp) { +ISC_TASKFUNC_SCOPE void +isc__task_attach(isc_task_t *source0, isc_task_t **targetp) { + isc__task_t *source = (isc__task_t *)source0; /* * Attach *targetp to source. @@ -242,11 +375,11 @@ isc_task_attach(isc_task_t *source, isc_task_t **targetp) { source->references++; UNLOCK(&source->lock); - *targetp = source; + *targetp = (isc_task_t *)source; } static inline isc_boolean_t -task_shutdown(isc_task_t *task) { +task_shutdown(isc__task_t *task) { isc_boolean_t was_idle = ISC_FALSE; isc_event_t *event, *prev; @@ -283,8 +416,8 @@ task_shutdown(isc_task_t *task) { } static inline void -task_ready(isc_task_t *task) { - isc_taskmgr_t *manager = task->manager; +task_ready(isc__task_t *task) { + isc__taskmgr_t *manager = task->manager; REQUIRE(VALID_MANAGER(manager)); REQUIRE(task->state == task_state_ready); @@ -294,15 +427,15 @@ task_ready(isc_task_t *task) { LOCK(&manager->lock); ENQUEUE(manager->ready_tasks, task, ready_link); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WORKER_THREADS SIGNAL(&manager->work_available); -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WORKER_THREADS */ UNLOCK(&manager->lock); } static inline isc_boolean_t -task_detach(isc_task_t *task) { +task_detach(isc__task_t *task) { /* * Caller must be holding the task lock. @@ -330,9 +463,9 @@ task_detach(isc_task_t *task) { return (ISC_FALSE); } -void -isc_task_detach(isc_task_t **taskp) { - isc_task_t *task; +ISC_TASKFUNC_SCOPE void +isc__task_detach(isc_task_t **taskp) { + isc__task_t *task; isc_boolean_t was_idle; /* @@ -340,7 +473,7 @@ isc_task_detach(isc_task_t **taskp) { */ REQUIRE(taskp != NULL); - task = *taskp; + task = (isc__task_t *)*taskp; REQUIRE(VALID_TASK(task)); XTRACE("isc_task_detach"); @@ -356,7 +489,7 @@ isc_task_detach(isc_task_t **taskp) { } static inline isc_boolean_t -task_send(isc_task_t *task, isc_event_t **eventp) { +task_send(isc__task_t *task, isc_event_t **eventp) { isc_boolean_t was_idle = ISC_FALSE; isc_event_t *event; @@ -385,8 +518,9 @@ task_send(isc_task_t *task, isc_event_t **eventp) { return (was_idle); } -void -isc_task_send(isc_task_t *task, isc_event_t **eventp) { +ISC_TASKFUNC_SCOPE void +isc__task_send(isc_task_t *task0, isc_event_t **eventp) { + isc__task_t *task = (isc__task_t *)task0; isc_boolean_t was_idle; /* @@ -426,10 +560,10 @@ isc_task_send(isc_task_t *task, isc_event_t **eventp) { } } -void -isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) { +ISC_TASKFUNC_SCOPE void +isc__task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) { isc_boolean_t idle1, idle2; - isc_task_t *task; + isc__task_t *task; /* * Send '*event' to '*taskp' and then detach '*taskp' from its @@ -437,7 +571,7 @@ isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) { */ REQUIRE(taskp != NULL); - task = *taskp; + task = (isc__task_t *)*taskp; REQUIRE(VALID_TASK(task)); XTRACE("isc_task_sendanddetach"); @@ -463,7 +597,7 @@ isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) { #define PURGE_OK(event) (((event)->ev_attributes & ISC_EVENTATTR_NOPURGE) == 0) static unsigned int -dequeue_events(isc_task_t *task, void *sender, isc_eventtype_t first, +dequeue_events(isc__task_t *task, void *sender, isc_eventtype_t first, isc_eventtype_t last, void *tag, isc_eventlist_t *events, isc_boolean_t purging) { @@ -502,10 +636,11 @@ dequeue_events(isc_task_t *task, void *sender, isc_eventtype_t first, return (count); } -unsigned int -isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first, - isc_eventtype_t last, void *tag) +ISC_TASKFUNC_SCOPE unsigned int +isc__task_purgerange(isc_task_t *task0, void *sender, isc_eventtype_t first, + isc_eventtype_t last, void *tag) { + isc__task_t *task = (isc__task_t *)task0; unsigned int count; isc_eventlist_t events; isc_event_t *event, *next_event; @@ -533,9 +668,9 @@ isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first, return (count); } -unsigned int -isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, - void *tag) +ISC_TASKFUNC_SCOPE unsigned int +isc__task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag) { /* * Purge events from a task's event queue. @@ -543,11 +678,12 @@ isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, XTRACE("isc_task_purge"); - return (isc_task_purgerange(task, sender, type, type, tag)); + return (isc__task_purgerange(task, sender, type, type, tag)); } -isc_boolean_t -isc_task_purgeevent(isc_task_t *task, isc_event_t *event) { +ISC_TASKFUNC_SCOPE isc_boolean_t +isc__task_purgeevent(isc_task_t *task0, isc_event_t *event) { + isc__task_t *task = (isc__task_t *)task0; isc_event_t *curr_event, *next_event; /* @@ -588,10 +724,10 @@ isc_task_purgeevent(isc_task_t *task, isc_event_t *event) { return (ISC_TRUE); } -unsigned int -isc_task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first, - isc_eventtype_t last, void *tag, - isc_eventlist_t *events) +ISC_TASKFUNC_SCOPE unsigned int +isc__task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first, + isc_eventtype_t last, void *tag, + isc_eventlist_t *events) { /* * Remove events from a task's event queue. @@ -599,13 +735,13 @@ isc_task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first, XTRACE("isc_task_unsendrange"); - return (dequeue_events(task, sender, first, last, tag, events, - ISC_FALSE)); + return (dequeue_events((isc__task_t *)task, sender, first, + last, tag, events, ISC_FALSE)); } -unsigned int -isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type, - void *tag, isc_eventlist_t *events) +ISC_TASKFUNC_SCOPE unsigned int +isc__task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag, isc_eventlist_t *events) { /* * Remove events from a task's event queue. @@ -613,13 +749,15 @@ isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type, XTRACE("isc_task_unsend"); - return (dequeue_events(task, sender, type, type, tag, events, - ISC_FALSE)); + return (dequeue_events((isc__task_t *)task, sender, type, + type, tag, events, ISC_FALSE)); } -isc_result_t -isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, const void *arg) +ISC_TASKFUNC_SCOPE isc_result_t +isc__task_onshutdown(isc_task_t *task0, isc_taskaction_t action, + const void *arg) { + isc__task_t *task = (isc__task_t *)task0; isc_boolean_t disallowed = ISC_FALSE; isc_result_t result = ISC_R_SUCCESS; isc_event_t *event; @@ -655,8 +793,9 @@ isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, const void *arg) return (result); } -void -isc_task_shutdown(isc_task_t *task) { +ISC_TASKFUNC_SCOPE void +isc__task_shutdown(isc_task_t *task0) { + isc__task_t *task = (isc__task_t *)task0; isc_boolean_t was_idle; /* @@ -673,8 +812,8 @@ isc_task_shutdown(isc_task_t *task) { task_ready(task); } -void -isc_task_destroy(isc_task_t **taskp) { +ISC_TASKFUNC_SCOPE void +isc__task_destroy(isc_task_t **taskp) { /* * Destroy '*taskp'. @@ -686,8 +825,9 @@ isc_task_destroy(isc_task_t **taskp) { isc_task_detach(taskp); } -void -isc_task_setname(isc_task_t *task, const char *name, void *tag) { +ISC_TASKFUNC_SCOPE void +isc__task_setname(isc_task_t *task0, const char *name, void *tag) { + isc__task_t *task = (isc__task_t *)task0; /* * Name 'task'. @@ -702,18 +842,28 @@ isc_task_setname(isc_task_t *task, const char *name, void *tag) { UNLOCK(&task->lock); } -const char * -isc_task_getname(isc_task_t *task) { +ISC_TASKFUNC_SCOPE const char * +isc__task_getname(isc_task_t *task0) { + isc__task_t *task = (isc__task_t *)task0; + + REQUIRE(VALID_TASK(task)); + return (task->name); } -void * -isc_task_gettag(isc_task_t *task) { +ISC_TASKFUNC_SCOPE void * +isc__task_gettag(isc_task_t *task0) { + isc__task_t *task = (isc__task_t *)task0; + + REQUIRE(VALID_TASK(task)); + return (task->tag); } -void -isc_task_getcurrenttime(isc_task_t *task, isc_stdtime_t *t) { +ISC_TASKFUNC_SCOPE void +isc__task_getcurrenttime(isc_task_t *task0, isc_stdtime_t *t) { + isc__task_t *task = (isc__task_t *)task0; + REQUIRE(VALID_TASK(task)); REQUIRE(t != NULL); @@ -728,12 +878,12 @@ isc_task_getcurrenttime(isc_task_t *task, isc_stdtime_t *t) { *** Task Manager. ***/ static void -dispatch(isc_taskmgr_t *manager) { - isc_task_t *task; -#ifndef ISC_PLATFORM_USETHREADS +dispatch(isc__taskmgr_t *manager) { + isc__task_t *task; +#ifndef USE_WORKER_THREADS unsigned int total_dispatch_count = 0; - isc_tasklist_t ready_tasks; -#endif /* ISC_PLATFORM_USETHREADS */ + isc__tasklist_t ready_tasks; +#endif /* USE_WORKER_THREADS */ REQUIRE(VALID_MANAGER(manager)); @@ -787,12 +937,12 @@ dispatch(isc_taskmgr_t *manager) { * unlocks. The while expression is always protected by the lock. */ -#ifndef ISC_PLATFORM_USETHREADS +#ifndef USE_WORKER_THREADS ISC_LIST_INIT(ready_tasks); #endif LOCK(&manager->lock); while (!FINISHED(manager)) { -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WORKER_THREADS /* * For reasons similar to those given in the comment in * isc_task_send() above, it is safe for us to dequeue @@ -812,11 +962,11 @@ dispatch(isc_taskmgr_t *manager) { ISC_MSGSET_TASK, ISC_MSG_AWAKE, "awake")); } -#else /* ISC_PLATFORM_USETHREADS */ +#else /* USE_WORKER_THREADS */ if (total_dispatch_count >= DEFAULT_TASKMGR_QUANTUM || EMPTY(manager->ready_tasks)) break; -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WORKER_THREADS */ XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TASK, ISC_MSG_WORKING, "working")); @@ -859,13 +1009,15 @@ dispatch(isc_taskmgr_t *manager) { "execute action")); if (event->ev_action != NULL) { UNLOCK(&task->lock); - (event->ev_action)(task,event); + (event->ev_action)( + (isc_task_t *)task, + event); LOCK(&task->lock); } dispatch_count++; -#ifndef ISC_PLATFORM_USETHREADS +#ifndef USE_WORKER_THREADS total_dispatch_count++; -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WORKER_THREADS */ } if (task->references == 0 && @@ -950,12 +1102,12 @@ dispatch(isc_taskmgr_t *manager) { LOCK(&manager->lock); manager->tasks_running--; -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WORKER_THREADS if (manager->exclusive_requested && manager->tasks_running == 1) { SIGNAL(&manager->exclusive_granted); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WORKER_THREADS */ if (requeue) { /* * We know we're awake, so we don't have @@ -976,7 +1128,7 @@ dispatch(isc_taskmgr_t *manager) { * were usually nonempty, the 'optimization' * might even hurt rather than help. */ -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WORKER_THREADS ENQUEUE(manager->ready_tasks, task, ready_link); #else @@ -985,19 +1137,19 @@ dispatch(isc_taskmgr_t *manager) { } } } -#ifndef ISC_PLATFORM_USETHREADS +#ifndef USE_WORKER_THREADS ISC_LIST_APPENDLIST(manager->ready_tasks, ready_tasks, ready_link); #endif UNLOCK(&manager->lock); } -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WORKER_THREADS static isc_threadresult_t #ifdef _WIN32 WINAPI #endif run(void *uap) { - isc_taskmgr_t *manager = uap; + isc__taskmgr_t *manager = uap; XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_STARTING, "starting")); @@ -1007,33 +1159,42 @@ run(void *uap) { XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_EXITING, "exiting")); +#ifdef OPENSSL_LEAKS + ERR_remove_state(0); +#endif + return ((isc_threadresult_t)0); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WORKER_THREADS */ static void -manager_free(isc_taskmgr_t *manager) { +manager_free(isc__taskmgr_t *manager) { isc_mem_t *mctx; -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WORKER_THREADS (void)isc_condition_destroy(&manager->exclusive_granted); (void)isc_condition_destroy(&manager->work_available); isc_mem_free(manager->mctx, manager->threads); -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WORKER_THREADS */ DESTROYLOCK(&manager->lock); - manager->magic = 0; + manager->common.impmagic = 0; + manager->common.magic = 0; mctx = manager->mctx; isc_mem_put(mctx, manager, sizeof(*manager)); isc_mem_detach(&mctx); + +#ifdef USE_SHARED_MANAGER + taskmgr = NULL; +#endif /* USE_SHARED_MANAGER */ } -isc_result_t -isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, - unsigned int default_quantum, isc_taskmgr_t **managerp) +ISC_TASKFUNC_SCOPE isc_result_t +isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers, + unsigned int default_quantum, isc_taskmgr_t **managerp) { isc_result_t result; unsigned int i, started = 0; - isc_taskmgr_t *manager; + isc__taskmgr_t *manager; /* * Create a new task manager. @@ -1042,28 +1203,33 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, REQUIRE(workers > 0); REQUIRE(managerp != NULL && *managerp == NULL); -#ifndef ISC_PLATFORM_USETHREADS +#ifndef USE_WORKER_THREADS UNUSED(i); UNUSED(started); - UNUSED(workers); +#endif +#ifdef USE_SHARED_MANAGER if (taskmgr != NULL) { + if (taskmgr->refs == 0) + return (ISC_R_SHUTTINGDOWN); taskmgr->refs++; - *managerp = taskmgr; + *managerp = (isc_taskmgr_t *)taskmgr; return (ISC_R_SUCCESS); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_SHARED_MANAGER */ manager = isc_mem_get(mctx, sizeof(*manager)); if (manager == NULL) return (ISC_R_NOMEMORY); - manager->magic = TASK_MANAGER_MAGIC; + manager->common.methods = &taskmgrmethods; + manager->common.impmagic = TASK_MANAGER_MAGIC; + manager->common.magic = ISCAPI_TASKMGR_MAGIC; manager->mctx = NULL; result = isc_mutex_init(&manager->lock); if (result != ISC_R_SUCCESS) goto cleanup_mgr; -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WORKER_THREADS manager->workers = 0; manager->threads = isc_mem_allocate(mctx, workers * sizeof(isc_thread_t)); @@ -1087,7 +1253,7 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, result = ISC_R_UNEXPECTED; goto cleanup_workavailable; } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WORKER_THREADS */ if (default_quantum == 0) default_quantum = DEFAULT_DEFAULT_QUANTUM; manager->default_quantum = default_quantum; @@ -1099,7 +1265,7 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, isc_mem_attach(mctx, &manager->mctx); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WORKER_THREADS LOCK(&manager->lock); /* * Start workers. @@ -1119,16 +1285,17 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, return (ISC_R_NOTHREADS); } isc_thread_setconcurrency(workers); -#else /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WORKER_THREADS */ +#ifdef USE_SHARED_MANAGER manager->refs = 1; taskmgr = manager; -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_SHARED_MANAGER */ - *managerp = manager; + *managerp = (isc_taskmgr_t *)manager; return (ISC_R_SUCCESS); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WORKER_THREADS cleanup_workavailable: (void)isc_condition_destroy(&manager->work_available); cleanup_threads: @@ -1141,10 +1308,10 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, return (result); } -void -isc_taskmgr_destroy(isc_taskmgr_t **managerp) { - isc_taskmgr_t *manager; - isc_task_t *task; +ISC_TASKFUNC_SCOPE void +isc__taskmgr_destroy(isc_taskmgr_t **managerp) { + isc__taskmgr_t *manager; + isc__task_t *task; unsigned int i; /* @@ -1152,18 +1319,20 @@ isc_taskmgr_destroy(isc_taskmgr_t **managerp) { */ REQUIRE(managerp != NULL); - manager = *managerp; + manager = (isc__taskmgr_t *)*managerp; REQUIRE(VALID_MANAGER(manager)); -#ifndef ISC_PLATFORM_USETHREADS +#ifndef USE_WORKER_THREADS UNUSED(i); +#endif /* USE_WORKER_THREADS */ - if (manager->refs > 1) { - manager->refs--; +#ifdef USE_SHARED_MANAGER + manager->refs--; + if (manager->refs > 0) { *managerp = NULL; return; } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif XTHREADTRACE("isc_taskmgr_destroy"); /* @@ -1203,7 +1372,7 @@ isc_taskmgr_destroy(isc_taskmgr_t **managerp) { ENQUEUE(manager->ready_tasks, task, ready_link); UNLOCK(&task->lock); } -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WORKER_THREADS /* * Wake up any sleeping workers. This ensures we get work done if * there's work left to do, and if there are already no tasks left @@ -1217,36 +1386,51 @@ isc_taskmgr_destroy(isc_taskmgr_t **managerp) { */ for (i = 0; i < manager->workers; i++) (void)isc_thread_join(manager->threads[i], NULL); -#else /* ISC_PLATFORM_USETHREADS */ +#else /* USE_WORKER_THREADS */ /* * Dispatch the shutdown events. */ UNLOCK(&manager->lock); - while (isc__taskmgr_ready()) - (void)isc__taskmgr_dispatch(); + while (isc__taskmgr_ready((isc_taskmgr_t *)manager)) + (void)isc__taskmgr_dispatch((isc_taskmgr_t *)manager); +#ifdef BIND9 if (!ISC_LIST_EMPTY(manager->tasks)) isc_mem_printallactive(stderr); +#endif INSIST(ISC_LIST_EMPTY(manager->tasks)); -#endif /* ISC_PLATFORM_USETHREADS */ +#ifdef USE_SHARED_MANAGER + taskmgr = NULL; +#endif +#endif /* USE_WORKER_THREADS */ manager_free(manager); *managerp = NULL; } -#ifndef ISC_PLATFORM_USETHREADS +#ifndef USE_WORKER_THREADS isc_boolean_t -isc__taskmgr_ready(void) { - if (taskmgr == NULL) +isc__taskmgr_ready(isc_taskmgr_t *manager0) { + isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; + +#ifdef USE_SHARED_MANAGER + if (manager == NULL) + manager = taskmgr; +#endif + if (manager == NULL) return (ISC_FALSE); - return (ISC_TF(!ISC_LIST_EMPTY(taskmgr->ready_tasks))); + return (ISC_TF(!ISC_LIST_EMPTY(manager->ready_tasks))); } isc_result_t -isc__taskmgr_dispatch(void) { - isc_taskmgr_t *manager = taskmgr; +isc__taskmgr_dispatch(isc_taskmgr_t *manager0) { + isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; - if (taskmgr == NULL) +#ifdef USE_SHARED_MANAGER + if (manager == NULL) + manager = taskmgr; +#endif + if (manager == NULL) return (ISC_R_NOTFOUND); dispatch(manager); @@ -1254,12 +1438,13 @@ isc__taskmgr_dispatch(void) { return (ISC_R_SUCCESS); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WORKER_THREADS */ -isc_result_t -isc_task_beginexclusive(isc_task_t *task) { -#ifdef ISC_PLATFORM_USETHREADS - isc_taskmgr_t *manager = task->manager; +ISC_TASKFUNC_SCOPE isc_result_t +isc__task_beginexclusive(isc_task_t *task0) { +#ifdef USE_WORKER_THREADS + isc__task_t *task = (isc__task_t *)task0; + isc__taskmgr_t *manager = task->manager; REQUIRE(task->state == task_state_running); LOCK(&manager->lock); if (manager->exclusive_requested) { @@ -1272,15 +1457,17 @@ isc_task_beginexclusive(isc_task_t *task) { } UNLOCK(&manager->lock); #else - UNUSED(task); + UNUSED(task0); #endif return (ISC_R_SUCCESS); } -void -isc_task_endexclusive(isc_task_t *task) { -#ifdef ISC_PLATFORM_USETHREADS - isc_taskmgr_t *manager = task->manager; +ISC_TASKFUNC_SCOPE void +isc__task_endexclusive(isc_task_t *task0) { +#ifdef USE_WORKER_THREADS + isc__task_t *task = (isc__task_t *)task0; + isc__taskmgr_t *manager = task->manager; + REQUIRE(task->state == task_state_running); LOCK(&manager->lock); REQUIRE(manager->exclusive_requested); @@ -1288,23 +1475,31 @@ isc_task_endexclusive(isc_task_t *task) { BROADCAST(&manager->work_available); UNLOCK(&manager->lock); #else - UNUSED(task); + UNUSED(task0); #endif } +#ifdef USE_SOCKETIMPREGISTER +isc_result_t +isc__task_register() { + return (isc_task_register(isc__taskmgr_create)); +} +#endif + isc_boolean_t isc_task_exiting(isc_task_t *t) { - isc_task_t *task = (isc_task_t *)t; + isc__task_t *task = (isc__task_t *)t; REQUIRE(VALID_TASK(task)); return (TASK_SHUTTINGDOWN(task)); } -#ifdef HAVE_LIBXML2 + +#if defined(HAVE_LIBXML2) && defined(BIND9) void -isc_taskmgr_renderxml(isc_taskmgr_t *mgr, xmlTextWriterPtr writer) -{ - isc_task_t *task; +isc_taskmgr_renderxml(isc_taskmgr_t *mgr0, xmlTextWriterPtr writer) { + isc__taskmgr_t *mgr = (isc__taskmgr_t *)mgr0; + isc__task_t *task; LOCK(&mgr->lock); @@ -1380,4 +1575,4 @@ isc_taskmgr_renderxml(isc_taskmgr_t *mgr, xmlTextWriterPtr writer) UNLOCK(&mgr->lock); } -#endif /* HAVE_LIBXML2 */ +#endif /* HAVE_LIBXML2 && BIND9 */ diff --git a/lib/isc/task_api.c b/lib/isc/task_api.c new file mode 100644 index 0000000..4e03db2 --- /dev/null +++ b/lib/isc/task_api.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: task_api.c,v 1.7 2010-12-22 23:46:59 tbox Exp $ */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +static isc_mutex_t createlock; +static isc_once_t once = ISC_ONCE_INIT; +static isc_taskmgrcreatefunc_t taskmgr_createfunc = NULL; + +static void +initialize(void) { + RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS); +} + +isc_result_t +isc_task_register(isc_taskmgrcreatefunc_t createfunc) { + isc_result_t result = ISC_R_SUCCESS; + + RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); + + LOCK(&createlock); + if (taskmgr_createfunc == NULL) + taskmgr_createfunc = createfunc; + else + result = ISC_R_EXISTS; + UNLOCK(&createlock); + + return (result); +} + +isc_result_t +isc_taskmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, + unsigned int workers, unsigned int default_quantum, + isc_taskmgr_t **managerp) +{ + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(taskmgr_createfunc != NULL); + result = (*taskmgr_createfunc)(mctx, workers, default_quantum, + managerp); + + UNLOCK(&createlock); + + if (result == ISC_R_SUCCESS) + isc_appctx_settaskmgr(actx, *managerp); + + return (result); +} + +isc_result_t +isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, + unsigned int default_quantum, isc_taskmgr_t **managerp) +{ + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(taskmgr_createfunc != NULL); + result = (*taskmgr_createfunc)(mctx, workers, default_quantum, + managerp); + + UNLOCK(&createlock); + + return (result); +} + +void +isc_taskmgr_destroy(isc_taskmgr_t **managerp) { + REQUIRE(managerp != NULL && ISCAPI_TASKMGR_VALID(*managerp)); + + (*managerp)->methods->destroy(managerp); + + ENSURE(*managerp == NULL); +} + +isc_result_t +isc_task_create(isc_taskmgr_t *manager, unsigned int quantum, + isc_task_t **taskp) +{ + REQUIRE(ISCAPI_TASKMGR_VALID(manager)); + REQUIRE(taskp != NULL && *taskp == NULL); + + return (manager->methods->taskcreate(manager, quantum, taskp)); +} + +void +isc_task_attach(isc_task_t *source, isc_task_t **targetp) { + REQUIRE(ISCAPI_TASK_VALID(source)); + REQUIRE(targetp != NULL && *targetp == NULL); + + source->methods->attach(source, targetp); + + ENSURE(*targetp == source); +} + +void +isc_task_detach(isc_task_t **taskp) { + REQUIRE(taskp != NULL && ISCAPI_TASK_VALID(*taskp)); + + (*taskp)->methods->detach(taskp); + + ENSURE(*taskp == NULL); +} + +void +isc_task_send(isc_task_t *task, isc_event_t **eventp) { + REQUIRE(ISCAPI_TASK_VALID(task)); + REQUIRE(eventp != NULL && *eventp != NULL); + + task->methods->send(task, eventp); + + ENSURE(*eventp == NULL); +} + +void +isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) { + REQUIRE(taskp != NULL && ISCAPI_TASK_VALID(*taskp)); + REQUIRE(eventp != NULL && *eventp != NULL); + + (*taskp)->methods->sendanddetach(taskp, eventp); + + ENSURE(*taskp == NULL && *eventp == NULL); +} + +unsigned int +isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag, isc_eventlist_t *events) +{ + REQUIRE(ISCAPI_TASK_VALID(task)); + + return (task->methods->unsend(task, sender, type, tag, events)); +} + +isc_result_t +isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, const void *arg) +{ + REQUIRE(ISCAPI_TASK_VALID(task)); + + return (task->methods->onshutdown(task, action, arg)); +} + +void +isc_task_shutdown(isc_task_t *task) { + REQUIRE(ISCAPI_TASK_VALID(task)); + + task->methods->shutdown(task); +} + +void +isc_task_setname(isc_task_t *task, const char *name, void *tag) { + REQUIRE(ISCAPI_TASK_VALID(task)); + + task->methods->setname(task, name, tag); +} + +unsigned int +isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, void *tag) +{ + REQUIRE(ISCAPI_TASK_VALID(task)); + + return (task->methods->purgeevents(task, sender, type, tag)); +} + +isc_result_t +isc_task_beginexclusive(isc_task_t *task) { + REQUIRE(ISCAPI_TASK_VALID(task)); + + return (task->methods->beginexclusive(task)); +} + +void +isc_task_endexclusive(isc_task_t *task) { + REQUIRE(ISCAPI_TASK_VALID(task)); + + task->methods->endexclusive(task); +} + + +/*% + * This is necessary for libisc's internal timer implementation. Other + * implementation might skip implementing this. + */ +unsigned int +isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first, + isc_eventtype_t last, void *tag) +{ + REQUIRE(ISCAPI_TASK_VALID(task)); + + return (task->methods->purgerange(task, sender, first, last, tag)); +} diff --git a/lib/isc/task_p.h b/lib/isc/task_p.h index 7bf208a..1bcdca6 100644 --- a/lib/isc/task_p.h +++ b/lib/isc/task_p.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: task_p.h,v 1.11 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: task_p.h,v 1.13 2009-09-02 23:48:02 tbox Exp $ */ #ifndef ISC_TASK_P_H #define ISC_TASK_P_H @@ -23,9 +23,9 @@ /*! \file */ isc_boolean_t -isc__taskmgr_ready(void); +isc__taskmgr_ready(isc_taskmgr_t *taskmgr); isc_result_t -isc__taskmgr_dispatch(void); +isc__taskmgr_dispatch(isc_taskmgr_t *taskmgr); #endif /* ISC_TASK_P_H */ diff --git a/lib/isc/timer.c b/lib/isc/timer.c index 6342688..ab89cdd 100644 --- a/lib/isc/timer.c +++ b/lib/isc/timer.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: timer.c,v 1.84.58.4 2009-01-23 23:47:21 tbox Exp $ */ +/* $Id: timer.c,v 1.95.302.1.2.1 2011-06-02 23:47:36 tbox Exp $ */ /*! \file */ @@ -34,9 +34,22 @@ #include #include -#ifndef ISC_PLATFORM_USETHREADS +#ifdef OPENSSL_LEAKS +#include +#endif + +/* See task.c about the following definition: */ +#ifdef BIND9 +#ifdef ISC_PLATFORM_USETHREADS +#define USE_TIMER_THREAD +#else +#define USE_SHARED_MANAGER +#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* BIND9 */ + +#ifndef USE_TIMER_THREAD #include "timer_p.h" -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_TIMER_THREAD */ #ifdef ISC_TIMER_TRACE #define XTRACE(s) fprintf(stderr, "%s\n", (s)) @@ -58,10 +71,13 @@ #define TIMER_MAGIC ISC_MAGIC('T', 'I', 'M', 'R') #define VALID_TIMER(t) ISC_MAGIC_VALID(t, TIMER_MAGIC) -struct isc_timer { +typedef struct isc__timer isc__timer_t; +typedef struct isc__timermgr isc__timermgr_t; + +struct isc__timer { /*! Not locked. */ - unsigned int magic; - isc_timermgr_t * manager; + isc_timer_t common; + isc__timermgr_t * manager; isc_mutex_t lock; /*! Locked by timer lock. */ unsigned int references; @@ -75,45 +91,119 @@ struct isc_timer { void * arg; unsigned int index; isc_time_t due; - LINK(isc_timer_t) link; + LINK(isc__timer_t) link; }; #define TIMER_MANAGER_MAGIC ISC_MAGIC('T', 'I', 'M', 'M') #define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TIMER_MANAGER_MAGIC) -struct isc_timermgr { +struct isc__timermgr { /* Not locked. */ - unsigned int magic; + isc_timermgr_t common; isc_mem_t * mctx; isc_mutex_t lock; /* Locked by manager lock. */ isc_boolean_t done; - LIST(isc_timer_t) timers; + LIST(isc__timer_t) timers; unsigned int nscheduled; isc_time_t due; -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_TIMER_THREAD isc_condition_t wakeup; isc_thread_t thread; -#else /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_TIMER_THREAD */ +#ifdef USE_SHARED_MANAGER unsigned int refs; -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_SHARED_MANAGER */ isc_heap_t * heap; }; -#ifndef ISC_PLATFORM_USETHREADS +/*% + * The followings can be either static or public, depending on build + * environment. + */ + +#ifdef BIND9 +#define ISC_TIMERFUNC_SCOPE +#else +#define ISC_TIMERFUNC_SCOPE static +#endif + +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timer_create(isc_timermgr_t *manager, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_timer_t **timerp); +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timer_reset(isc_timer_t *timer, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_boolean_t purge); +ISC_TIMERFUNC_SCOPE isc_timertype_t +isc__timer_gettype(isc_timer_t *timer); +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timer_touch(isc_timer_t *timer); +ISC_TIMERFUNC_SCOPE void +isc__timer_attach(isc_timer_t *timer0, isc_timer_t **timerp); +ISC_TIMERFUNC_SCOPE void +isc__timer_detach(isc_timer_t **timerp); +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp); +ISC_TIMERFUNC_SCOPE void +isc__timermgr_poke(isc_timermgr_t *manager0); +ISC_TIMERFUNC_SCOPE void +isc__timermgr_destroy(isc_timermgr_t **managerp); + +static struct isc__timermethods { + isc_timermethods_t methods; + + /*% + * The following are defined just for avoiding unused static functions. + */ +#ifndef BIND9 + void *gettype; +#endif +} timermethods = { + { + isc__timer_attach, + isc__timer_detach, + isc__timer_reset, + isc__timer_touch + } +#ifndef BIND9 + , + (void *)isc__timer_gettype +#endif +}; + +static struct isc__timermgrmethods { + isc_timermgrmethods_t methods; +#ifndef BIND9 + void *poke; /* see above */ +#endif +} timermgrmethods = { + { + isc__timermgr_destroy, + isc__timer_create + } +#ifndef BIND9 + , + (void *)isc__timermgr_poke +#endif +}; + +#ifdef USE_SHARED_MANAGER /*! - * If threads are not in use, there can be only one. + * If the manager is supposed to be shared, there can be only one. */ -static isc_timermgr_t *timermgr = NULL; -#endif /* ISC_PLATFORM_USETHREADS */ +static isc__timermgr_t *timermgr = NULL; +#endif /* USE_SHARED_MANAGER */ static inline isc_result_t -schedule(isc_timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) { +schedule(isc__timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) { isc_result_t result; - isc_timermgr_t *manager; + isc__timermgr_t *manager; isc_time_t due; int cmp; -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_TIMER_THREAD isc_boolean_t timedwait; #endif @@ -123,13 +213,13 @@ schedule(isc_timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) { REQUIRE(timer->type != isc_timertype_inactive); -#ifndef ISC_PLATFORM_USETHREADS +#ifndef USE_TIMER_THREAD UNUSED(signal_ok); -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_TIMER_THREAD */ manager = timer->manager; -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_TIMER_THREAD /*! * If the manager was timed wait, we may need to signal the * manager to force a wakeup. @@ -199,7 +289,7 @@ schedule(isc_timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) { * the current "next" timer. We do this either by waking up the * run thread, or explicitly setting the value in the manager. */ -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_TIMER_THREAD /* * This is a temporary (probably) hack to fix a bug on tru64 5.1 @@ -232,19 +322,19 @@ schedule(isc_timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) { "signal (schedule)")); SIGNAL(&manager->wakeup); } -#else /* ISC_PLATFORM_USETHREADS */ +#else /* USE_TIMER_THREAD */ if (timer->index == 1 && isc_time_compare(&timer->due, &manager->due) < 0) manager->due = timer->due; -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_TIMER_THREAD */ return (ISC_R_SUCCESS); } static inline void -deschedule(isc_timer_t *timer) { +deschedule(isc__timer_t *timer) { isc_boolean_t need_wakeup = ISC_FALSE; - isc_timermgr_t *manager; + isc__timermgr_t *manager; /* * The caller must ensure locking. @@ -258,20 +348,20 @@ deschedule(isc_timer_t *timer) { timer->index = 0; INSIST(manager->nscheduled > 0); manager->nscheduled--; -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_TIMER_THREAD if (need_wakeup) { XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_SIGNALDESCHED, "signal (deschedule)")); SIGNAL(&manager->wakeup); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_TIMER_THREAD */ } } static void -destroy(isc_timer_t *timer) { - isc_timermgr_t *manager = timer->manager; +destroy(isc__timer_t *timer) { + isc__timermgr_t *manager = timer->manager; /* * The caller must ensure it is safe to destroy the timer. @@ -291,17 +381,19 @@ destroy(isc_timer_t *timer) { isc_task_detach(&timer->task); DESTROYLOCK(&timer->lock); - timer->magic = 0; + timer->common.impmagic = 0; + timer->common.magic = 0; isc_mem_put(manager->mctx, timer, sizeof(*timer)); } -isc_result_t -isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type, - isc_time_t *expires, isc_interval_t *interval, - isc_task_t *task, isc_taskaction_t action, const void *arg, - isc_timer_t **timerp) +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timer_create(isc_timermgr_t *manager0, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_timer_t **timerp) { - isc_timer_t *timer; + isc__timermgr_t *manager = (isc__timermgr_t *)manager0; + isc__timer_t *timer; isc_result_t result; isc_time_t now; @@ -382,7 +474,9 @@ isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type, return (result); } ISC_LINK_INIT(timer, link); - timer->magic = TIMER_MAGIC; + timer->common.impmagic = TIMER_MAGIC; + timer->common.magic = ISCAPI_TIMER_MAGIC; + timer->common.methods = (isc_timermethods_t *)&timermethods; LOCK(&manager->lock); @@ -401,25 +495,27 @@ isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type, UNLOCK(&manager->lock); if (result != ISC_R_SUCCESS) { - timer->magic = 0; + timer->common.impmagic = 0; + timer->common.magic = 0; DESTROYLOCK(&timer->lock); isc_task_detach(&timer->task); isc_mem_put(manager->mctx, timer, sizeof(*timer)); return (result); } - *timerp = timer; + *timerp = (isc_timer_t *)timer; return (ISC_R_SUCCESS); } -isc_result_t -isc_timer_reset(isc_timer_t *timer, isc_timertype_t type, - isc_time_t *expires, isc_interval_t *interval, - isc_boolean_t purge) +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timer_reset(isc_timer_t *timer0, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_boolean_t purge) { + isc__timer_t *timer = (isc__timer_t *)timer0; isc_time_t now; - isc_timermgr_t *manager; + isc__timermgr_t *manager; isc_result_t result; /* @@ -489,8 +585,9 @@ isc_timer_reset(isc_timer_t *timer, isc_timertype_t type, return (result); } -isc_timertype_t -isc_timer_gettype(isc_timer_t *timer) { +ISC_TIMERFUNC_SCOPE isc_timertype_t +isc__timer_gettype(isc_timer_t *timer0) { + isc__timer_t *timer = (isc__timer_t *)timer0; isc_timertype_t t; REQUIRE(VALID_TIMER(timer)); @@ -502,8 +599,9 @@ isc_timer_gettype(isc_timer_t *timer) { return (t); } -isc_result_t -isc_timer_touch(isc_timer_t *timer) { +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timer_touch(isc_timer_t *timer0) { + isc__timer_t *timer = (isc__timer_t *)timer0; isc_result_t result; isc_time_t now; @@ -532,8 +630,10 @@ isc_timer_touch(isc_timer_t *timer) { return (result); } -void -isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp) { +ISC_TIMERFUNC_SCOPE void +isc__timer_attach(isc_timer_t *timer0, isc_timer_t **timerp) { + isc__timer_t *timer = (isc__timer_t *)timer0; + /* * Attach *timerp to timer. */ @@ -545,12 +645,12 @@ isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp) { timer->references++; UNLOCK(&timer->lock); - *timerp = timer; + *timerp = (isc_timer_t *)timer; } -void -isc_timer_detach(isc_timer_t **timerp) { - isc_timer_t *timer; +ISC_TIMERFUNC_SCOPE void +isc__timer_detach(isc_timer_t **timerp) { + isc__timer_t *timer; isc_boolean_t free_timer = ISC_FALSE; /* @@ -558,7 +658,7 @@ isc_timer_detach(isc_timer_t **timerp) { */ REQUIRE(timerp != NULL); - timer = *timerp; + timer = (isc__timer_t *)*timerp; REQUIRE(VALID_TIMER(timer)); LOCK(&timer->lock); @@ -575,11 +675,11 @@ isc_timer_detach(isc_timer_t **timerp) { } static void -dispatch(isc_timermgr_t *manager, isc_time_t *now) { +dispatch(isc__timermgr_t *manager, isc_time_t *now) { isc_boolean_t done = ISC_FALSE, post_event, need_schedule; isc_timerevent_t *event; isc_eventtype_t type = 0; - isc_timer_t *timer; + isc__timer_t *timer; isc_result_t result; isc_boolean_t idle; @@ -693,13 +793,13 @@ dispatch(isc_timermgr_t *manager, isc_time_t *now) { } } -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_TIMER_THREAD static isc_threadresult_t #ifdef _WIN32 /* XXXDCL */ WINAPI #endif run(void *uap) { - isc_timermgr_t *manager = uap; + isc__timermgr_t *manager = uap; isc_time_t now; isc_result_t result; @@ -732,13 +832,17 @@ run(void *uap) { } UNLOCK(&manager->lock); +#ifdef OPENSSL_LEAKS + ERR_remove_state(0); +#endif + return ((isc_threadresult_t)0); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_TIMER_THREAD */ static isc_boolean_t sooner(void *v1, void *v2) { - isc_timer_t *t1, *t2; + isc__timer_t *t1, *t2; t1 = v1; t2 = v2; @@ -752,7 +856,7 @@ sooner(void *v1, void *v2) { static void set_index(void *what, unsigned int index) { - isc_timer_t *timer; + isc__timer_t *timer; timer = what; REQUIRE(VALID_TIMER(timer)); @@ -760,9 +864,9 @@ set_index(void *what, unsigned int index) { timer->index = index; } -isc_result_t -isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { - isc_timermgr_t *manager; +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { + isc__timermgr_t *manager; isc_result_t result; /* @@ -771,19 +875,21 @@ isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { REQUIRE(managerp != NULL && *managerp == NULL); -#ifndef ISC_PLATFORM_USETHREADS +#ifdef USE_SHARED_MANAGER if (timermgr != NULL) { timermgr->refs++; - *managerp = timermgr; + *managerp = (isc_timermgr_t *)timermgr; return (ISC_R_SUCCESS); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_SHARED_MANAGER */ manager = isc_mem_get(mctx, sizeof(*manager)); if (manager == NULL) return (ISC_R_NOMEMORY); - manager->magic = TIMER_MANAGER_MAGIC; + manager->common.impmagic = TIMER_MANAGER_MAGIC; + manager->common.magic = ISCAPI_TIMERMGR_MAGIC; + manager->common.methods = (isc_timermgrmethods_t *)&timermgrmethods; manager->mctx = NULL; manager->done = ISC_FALSE; INIT_LIST(manager->timers); @@ -803,7 +909,7 @@ isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { return (result); } isc_mem_attach(mctx, &manager->mctx); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_TIMER_THREAD if (isc_condition_init(&manager->wakeup) != ISC_R_SUCCESS) { isc_mem_detach(&manager->mctx); DESTROYLOCK(&manager->lock); @@ -828,30 +934,33 @@ isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { ISC_MSG_FAILED, "failed")); return (ISC_R_UNEXPECTED); } -#else /* ISC_PLATFORM_USETHREADS */ +#endif +#ifdef USE_SHARED_MANAGER manager->refs = 1; timermgr = manager; -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_SHARED_MANAGER */ - *managerp = manager; + *managerp = (isc_timermgr_t *)manager; return (ISC_R_SUCCESS); } -void -isc_timermgr_poke(isc_timermgr_t *manager) { -#ifdef ISC_PLATFORM_USETHREADS +ISC_TIMERFUNC_SCOPE void +isc__timermgr_poke(isc_timermgr_t *manager0) { +#ifdef USE_TIMER_THREAD + isc__timermgr_t *manager = (isc__timermgr_t *)manager0; + REQUIRE(VALID_MANAGER(manager)); SIGNAL(&manager->wakeup); #else - UNUSED(manager); + UNUSED(manager0); #endif } -void -isc_timermgr_destroy(isc_timermgr_t **managerp) { - isc_timermgr_t *manager; +ISC_TIMERFUNC_SCOPE void +isc__timermgr_destroy(isc_timermgr_t **managerp) { + isc__timermgr_t *manager; isc_mem_t *mctx; /* @@ -859,34 +968,37 @@ isc_timermgr_destroy(isc_timermgr_t **managerp) { */ REQUIRE(managerp != NULL); - manager = *managerp; + manager = (isc__timermgr_t *)*managerp; REQUIRE(VALID_MANAGER(manager)); LOCK(&manager->lock); -#ifndef ISC_PLATFORM_USETHREADS - if (manager->refs > 1) { - manager->refs--; +#ifdef USE_SHARED_MANAGER + manager->refs--; + if (manager->refs > 0) { UNLOCK(&manager->lock); *managerp = NULL; return; } + timermgr = NULL; +#endif /* USE_SHARED_MANAGER */ - isc__timermgr_dispatch(); -#endif /* ISC_PLATFORM_USETHREADS */ +#ifndef USE_TIMER_THREAD + isc__timermgr_dispatch((isc_timermgr_t *)manager); +#endif REQUIRE(EMPTY(manager->timers)); manager->done = ISC_TRUE; -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_TIMER_THREAD XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_SIGNALDESTROY, "signal (destroy)")); SIGNAL(&manager->wakeup); -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_TIMER_THREAD */ UNLOCK(&manager->lock); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_TIMER_THREAD /* * Wait for thread to exit. */ @@ -895,39 +1007,63 @@ isc_timermgr_destroy(isc_timermgr_t **managerp) { "isc_thread_join() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_TIMER_THREAD */ /* * Clean up. */ -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_TIMER_THREAD (void)isc_condition_destroy(&manager->wakeup); -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_TIMER_THREAD */ DESTROYLOCK(&manager->lock); isc_heap_destroy(&manager->heap); - manager->magic = 0; + manager->common.impmagic = 0; + manager->common.magic = 0; mctx = manager->mctx; isc_mem_put(mctx, manager, sizeof(*manager)); isc_mem_detach(&mctx); *managerp = NULL; + +#ifdef USE_SHARED_MANAGER + timermgr = NULL; +#endif } -#ifndef ISC_PLATFORM_USETHREADS +#ifndef USE_TIMER_THREAD isc_result_t -isc__timermgr_nextevent(isc_time_t *when) { - if (timermgr == NULL || timermgr->nscheduled == 0) +isc__timermgr_nextevent(isc_timermgr_t *manager0, isc_time_t *when) { + isc__timermgr_t *manager = (isc__timermgr_t *)manager0; + +#ifdef USE_SHARED_MANAGER + if (manager == NULL) + manager = timermgr; +#endif + if (manager == NULL || manager->nscheduled == 0) return (ISC_R_NOTFOUND); - *when = timermgr->due; + *when = manager->due; return (ISC_R_SUCCESS); } void -isc__timermgr_dispatch(void) { +isc__timermgr_dispatch(isc_timermgr_t *manager0) { + isc__timermgr_t *manager = (isc__timermgr_t *)manager0; isc_time_t now; - if (timermgr == NULL) + +#ifdef USE_SHARED_MANAGER + if (manager == NULL) + manager = timermgr; +#endif + if (manager == NULL) return; TIME_NOW(&now); - dispatch(timermgr, &now); + dispatch(manager, &now); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_TIMER_THREAD */ + +#ifdef USE_TIMERIMPREGISTER +isc_result_t +isc__timer_register() { + return (isc_timer_register(isc__timermgr_create)); +} +#endif diff --git a/lib/isc/timer_api.c b/lib/isc/timer_api.c new file mode 100644 index 0000000..5a9bf9d --- /dev/null +++ b/lib/isc/timer_api.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: timer_api.c,v 1.4 2009-09-02 23:48:02 tbox Exp $ */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +static isc_mutex_t createlock; +static isc_once_t once = ISC_ONCE_INIT; +static isc_timermgrcreatefunc_t timermgr_createfunc = NULL; + +static void +initialize(void) { + RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS); +} + +isc_result_t +isc_timer_register(isc_timermgrcreatefunc_t createfunc) { + isc_result_t result = ISC_R_SUCCESS; + + RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); + + LOCK(&createlock); + if (timermgr_createfunc == NULL) + timermgr_createfunc = createfunc; + else + result = ISC_R_EXISTS; + UNLOCK(&createlock); + + return (result); +} + +isc_result_t +isc_timermgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, + isc_timermgr_t **managerp) +{ + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(timermgr_createfunc != NULL); + result = (*timermgr_createfunc)(mctx, managerp); + + UNLOCK(&createlock); + + if (result == ISC_R_SUCCESS) + isc_appctx_settimermgr(actx, *managerp); + + return (result); +} + +isc_result_t +isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(timermgr_createfunc != NULL); + result = (*timermgr_createfunc)(mctx, managerp); + + UNLOCK(&createlock); + + return (result); +} + +void +isc_timermgr_destroy(isc_timermgr_t **managerp) { + REQUIRE(*managerp != NULL && ISCAPI_TIMERMGR_VALID(*managerp)); + + (*managerp)->methods->destroy(managerp); + + ENSURE(*managerp == NULL); +} + +isc_result_t +isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_timer_t **timerp) +{ + REQUIRE(ISCAPI_TIMERMGR_VALID(manager)); + + return (manager->methods->timercreate(manager, type, expires, + interval, task, action, arg, + timerp)); +} + +void +isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp) { + REQUIRE(ISCAPI_TIMER_VALID(timer)); + REQUIRE(timerp != NULL && *timerp == NULL); + + timer->methods->attach(timer, timerp); + + ENSURE(*timerp == timer); +} + +void +isc_timer_detach(isc_timer_t **timerp) { + REQUIRE(timerp != NULL && ISCAPI_TIMER_VALID(*timerp)); + + (*timerp)->methods->detach(timerp); + + ENSURE(*timerp == NULL); +} + +isc_result_t +isc_timer_reset(isc_timer_t *timer, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_boolean_t purge) +{ + REQUIRE(ISCAPI_TIMER_VALID(timer)); + + return (timer->methods->reset(timer, type, expires, interval, purge)); +} + +isc_result_t +isc_timer_touch(isc_timer_t *timer) { + REQUIRE(ISCAPI_TIMER_VALID(timer)); + + return (timer->methods->touch(timer)); +} diff --git a/lib/isc/timer_p.h b/lib/isc/timer_p.h index b41f922..657b695 100644 --- a/lib/isc/timer_p.h +++ b/lib/isc/timer_p.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: timer_p.h,v 1.10 2007-06-19 23:47:17 tbox Exp $ */ +/* $Id: timer_p.h,v 1.12 2009-09-02 23:48:02 tbox Exp $ */ #ifndef ISC_TIMER_P_H #define ISC_TIMER_P_H @@ -23,9 +23,9 @@ /*! \file */ isc_result_t -isc__timermgr_nextevent(isc_time_t *when); +isc__timermgr_nextevent(isc_timermgr_t *timermgr, isc_time_t *when); void -isc__timermgr_dispatch(void); +isc__timermgr_dispatch(isc_timermgr_t *timermgr); #endif /* ISC_TIMER_P_H */ diff --git a/lib/isc/unix/Makefile.in b/lib/isc/unix/Makefile.in index 7d23b96..2c91756 100644 --- a/lib/isc/unix/Makefile.in +++ b/lib/isc/unix/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 1998-2001 Internet Software Consortium. # # Permission to use, copy, modify, and/or distribute this software for any @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.41 2007-06-19 23:47:18 tbox Exp $ +# $Id: Makefile.in,v 1.44 2009-12-05 23:31:41 each Exp $ srcdir = @srcdir@ VPATH = @srcdir@ diff --git a/lib/isc/unix/app.c b/lib/isc/unix/app.c index 6bd1660..4dc5130 100644 --- a/lib/isc/unix/app.c +++ b/lib/isc/unix/app.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: app.c,v 1.60 2008-10-15 03:41:17 marka Exp $ */ +/* $Id: app.c,v 1.64 2009-11-04 05:58:46 marka Exp $ */ /*! \file */ @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -47,31 +48,129 @@ #include #include +/*% + * For BIND9 internal applications built with threads, we use a single app + * context and let multiple worker, I/O, timer threads do actual jobs. + * For other cases (including BIND9 built without threads) an app context acts + * as an event loop dispatching various events. + */ +#if defined(ISC_PLATFORM_USETHREADS) && defined(BIND9) +#define USE_THREADS_SINGLECTX +#endif + #ifdef ISC_PLATFORM_USETHREADS #include -#else /* ISC_PLATFORM_USETHREADS */ +#endif + +#ifndef USE_THREADS_SINGLECTX #include "../timer_p.h" #include "../task_p.h" #include "socket_p.h" +#endif /* USE_THREADS_SINGLECTX */ + +#ifdef ISC_PLATFORM_USETHREADS +static pthread_t blockedthread; #endif /* ISC_PLATFORM_USETHREADS */ -static isc_eventlist_t on_run; -static isc_mutex_t lock; -static isc_boolean_t shutdown_requested = ISC_FALSE; -static isc_boolean_t running = ISC_FALSE; -/*! - * We assume that 'want_shutdown' can be read and written atomically. +/*% + * The following can be either static or public, depending on build environment. */ -static volatile isc_boolean_t want_shutdown = ISC_FALSE; + +#ifdef BIND9 +#define ISC_APPFUNC_SCOPE +#else +#define ISC_APPFUNC_SCOPE static +#endif + +ISC_APPFUNC_SCOPE isc_result_t isc__app_start(void); +ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxstart(isc_appctx_t *ctx); +ISC_APPFUNC_SCOPE isc_result_t isc__app_onrun(isc_mem_t *mctx, + isc_task_t *task, + isc_taskaction_t action, + void *arg); +ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxrun(isc_appctx_t *ctx); +ISC_APPFUNC_SCOPE isc_result_t isc__app_run(void); +ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxshutdown(isc_appctx_t *ctx); +ISC_APPFUNC_SCOPE isc_result_t isc__app_shutdown(void); +ISC_APPFUNC_SCOPE isc_result_t isc__app_reload(void); +ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxsuspend(isc_appctx_t *ctx); +ISC_APPFUNC_SCOPE void isc__app_ctxfinish(isc_appctx_t *ctx); +ISC_APPFUNC_SCOPE void isc__app_finish(void); +ISC_APPFUNC_SCOPE void isc__app_block(void); +ISC_APPFUNC_SCOPE void isc__app_unblock(void); +ISC_APPFUNC_SCOPE isc_result_t isc__appctx_create(isc_mem_t *mctx, + isc_appctx_t **ctxp); +ISC_APPFUNC_SCOPE void isc__appctx_destroy(isc_appctx_t **ctxp); +ISC_APPFUNC_SCOPE void isc__appctx_settaskmgr(isc_appctx_t *ctx, + isc_taskmgr_t *taskmgr); +ISC_APPFUNC_SCOPE void isc__appctx_setsocketmgr(isc_appctx_t *ctx, + isc_socketmgr_t *socketmgr); +ISC_APPFUNC_SCOPE void isc__appctx_settimermgr(isc_appctx_t *ctx, + isc_timermgr_t *timermgr); + /* - * We assume that 'want_reload' can be read and written atomically. + * The application context of this module. This implementation actually + * doesn't use it. (This may change in the future). */ -static volatile isc_boolean_t want_reload = ISC_FALSE; +#define APPCTX_MAGIC ISC_MAGIC('A', 'p', 'c', 'x') +#define VALID_APPCTX(c) ISC_MAGIC_VALID(c, APPCTX_MAGIC) + +typedef struct isc__appctx { + isc_appctx_t common; + isc_mem_t *mctx; + isc_mutex_t lock; + isc_eventlist_t on_run; + isc_boolean_t shutdown_requested; + isc_boolean_t running; + + /*! + * We assume that 'want_shutdown' can be read and written atomically. + */ + isc_boolean_t want_shutdown; + /* + * We assume that 'want_reload' can be read and written atomically. + */ + isc_boolean_t want_reload; -static isc_boolean_t blocked = ISC_FALSE; -#ifdef ISC_PLATFORM_USETHREADS -static pthread_t blockedthread; -#endif /* ISC_PLATFORM_USETHREADS */ + isc_boolean_t blocked; + + isc_taskmgr_t *taskmgr; + isc_socketmgr_t *socketmgr; + isc_timermgr_t *timermgr; +} isc__appctx_t; + +static isc__appctx_t isc_g_appctx; + +static struct { + isc_appmethods_t methods; + + /*% + * The following are defined just for avoiding unused static functions. + */ +#ifndef BIND9 + void *run, *shutdown, *start, *onrun, *reload, *finish, + *block, *unblock; +#endif +} appmethods = { + { + isc__appctx_destroy, + isc__app_ctxstart, + isc__app_ctxrun, + isc__app_ctxsuspend, + isc__app_ctxshutdown, + isc__app_ctxfinish, + isc__appctx_settaskmgr, + isc__appctx_setsocketmgr, + isc__appctx_settimermgr + } +#ifndef BIND9 + , + (void *)isc__app_run, (void *)isc__app_shutdown, + (void *)isc__app_start, (void *)isc__app_onrun, (void *)isc__app_reload, + (void *)isc__app_finish, (void *)isc__app_block, + (void *)isc__app_unblock +#endif +}; #ifdef HAVE_LINUXTHREADS /*! @@ -91,13 +190,13 @@ static pthread_t main_thread; static void exit_action(int arg) { UNUSED(arg); - want_shutdown = ISC_TRUE; + isc_g_appctx.want_shutdown = ISC_TRUE; } static void reload_action(int arg) { UNUSED(arg); - want_reload = ISC_TRUE; + isc_g_appctx.want_reload = ISC_TRUE; } #endif @@ -123,12 +222,12 @@ handle_signal(int sig, void (*handler)(int)) { return (ISC_R_SUCCESS); } -isc_result_t -isc_app_start(void) { +ISC_APPFUNC_SCOPE isc_result_t +isc__app_ctxstart(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; isc_result_t result; - int presult; - sigset_t sset; - char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(VALID_APPCTX(ctx)); /* * Start an ISC library application. @@ -151,7 +250,35 @@ isc_app_start(void) { main_thread = pthread_self(); #endif - result = isc_mutex_init(&lock); + result = isc_mutex_init(&ctx->lock); + if (result != ISC_R_SUCCESS) + return (result); + + ISC_LIST_INIT(ctx->on_run); + + ctx->shutdown_requested = ISC_FALSE; + ctx->running = ISC_FALSE; + ctx->want_shutdown = ISC_FALSE; + ctx->want_reload = ISC_FALSE; + ctx->blocked = ISC_FALSE; + + return (ISC_R_SUCCESS); +} + +ISC_APPFUNC_SCOPE isc_result_t +isc__app_start(void) { + isc_result_t result; + int presult; + sigset_t sset; + char strbuf[ISC_STRERRORSIZE]; + + isc_g_appctx.common.impmagic = APPCTX_MAGIC; + isc_g_appctx.common.magic = ISCAPI_APPCTX_MAGIC; + isc_g_appctx.common.methods = &appmethods.methods; + isc_g_appctx.mctx = NULL; + /* The remaining members will be initialized in ctxstart() */ + + result = isc__app_ctxstart((isc_appctx_t *)&isc_g_appctx); if (result != ISC_R_SUCCESS) return (result); @@ -253,22 +380,20 @@ isc_app_start(void) { } #endif /* ISC_PLATFORM_USETHREADS */ - ISC_LIST_INIT(on_run); - return (ISC_R_SUCCESS); } -isc_result_t -isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, +ISC_APPFUNC_SCOPE isc_result_t +isc__app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, void *arg) { isc_event_t *event; isc_task_t *cloned_task = NULL; isc_result_t result; - LOCK(&lock); + LOCK(&isc_g_appctx.lock); - if (running) { + if (isc_g_appctx.running) { result = ISC_R_ALREADYRUNNING; goto unlock; } @@ -285,24 +410,25 @@ isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, goto unlock; } - ISC_LIST_APPEND(on_run, event, ev_link); + ISC_LIST_APPEND(isc_g_appctx.on_run, event, ev_link); result = ISC_R_SUCCESS; unlock: - UNLOCK(&lock); + UNLOCK(&isc_g_appctx.lock); return (result); } -#ifndef ISC_PLATFORM_USETHREADS +#ifndef USE_THREADS_SINGLECTX /*! * Event loop for nonthreaded programs. */ static isc_result_t -evloop(void) { +evloop(isc__appctx_t *ctx) { isc_result_t result; - while (!want_shutdown) { + + while (!ctx->want_shutdown) { int n; isc_time_t when, now; struct timeval tv, *tvp; @@ -310,14 +436,27 @@ evloop(void) { isc_boolean_t readytasks; isc_boolean_t call_timer_dispatch = ISC_FALSE; - readytasks = isc__taskmgr_ready(); + /* + * Check the reload (or suspend) case first for exiting the + * loop as fast as possible in case: + * - the direct call to isc__taskmgr_dispatch() in + * isc__app_ctxrun() completes all the tasks so far, + * - there is thus currently no active task, and + * - there is a timer event + */ + if (ctx->want_reload) { + ctx->want_reload = ISC_FALSE; + return (ISC_R_RELOAD); + } + + readytasks = isc__taskmgr_ready(ctx->taskmgr); if (readytasks) { tv.tv_sec = 0; tv.tv_usec = 0; tvp = &tv; call_timer_dispatch = ISC_TRUE; } else { - result = isc__timermgr_nextevent(&when); + result = isc__timermgr_nextevent(ctx->timermgr, &when); if (result != ISC_R_SUCCESS) tvp = NULL; else { @@ -334,7 +473,7 @@ evloop(void) { } swait = NULL; - n = isc__socketmgr_waitevents(tvp, &swait); + n = isc__socketmgr_waitevents(ctx->socketmgr, tvp, &swait); if (n == 0 || call_timer_dispatch) { /* @@ -351,20 +490,17 @@ evloop(void) { * call, since this loop only runs in the non-thread * mode. */ - isc__timermgr_dispatch(); + isc__timermgr_dispatch(ctx->timermgr); } if (n > 0) - (void)isc__socketmgr_dispatch(swait); - (void)isc__taskmgr_dispatch(); - - if (want_reload) { - want_reload = ISC_FALSE; - return (ISC_R_RELOAD); - } + (void)isc__socketmgr_dispatch(ctx->socketmgr, swait); + (void)isc__taskmgr_dispatch(ctx->taskmgr); } return (ISC_R_SUCCESS); } +#endif /* USE_THREADS_SINGLECTX */ +#ifndef ISC_PLATFORM_USETHREADS /* * This is a gross hack to support waiting for condition * variables in nonthreaded programs in a limited way; @@ -400,11 +536,11 @@ isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp) { INSIST(*mp == 1); /* Mutex must be locked on entry. */ --*mp; - result = evloop(); + result = evloop(&isc_g_appctx); if (result == ISC_R_RELOAD) - want_reload = ISC_TRUE; + isc_g_appctx.want_reload = ISC_TRUE; if (signalled) { - want_shutdown = ISC_FALSE; + isc_g_appctx.want_shutdown = ISC_FALSE; signalled = ISC_FALSE; } @@ -420,43 +556,46 @@ isc__nothread_signal_hack(isc_condition_t *cp) { INSIST(in_recursive_evloop); - want_shutdown = ISC_TRUE; + isc_g_appctx.want_shutdown = ISC_TRUE; signalled = ISC_TRUE; return (ISC_R_SUCCESS); } #endif /* ISC_PLATFORM_USETHREADS */ -isc_result_t -isc_app_run(void) { +ISC_APPFUNC_SCOPE isc_result_t +isc__app_ctxrun(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; int result; isc_event_t *event, *next_event; isc_task_t *task; -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_THREADS_SINGLECTX sigset_t sset; char strbuf[ISC_STRERRORSIZE]; #ifdef HAVE_SIGWAIT int sig; #endif -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_THREADS_SINGLECTX */ + + REQUIRE(VALID_APPCTX(ctx)); #ifdef HAVE_LINUXTHREADS REQUIRE(main_thread == pthread_self()); #endif - LOCK(&lock); + LOCK(&ctx->lock); - if (!running) { - running = ISC_TRUE; + if (!ctx->running) { + ctx->running = ISC_TRUE; /* * Post any on-run events (in FIFO order). */ - for (event = ISC_LIST_HEAD(on_run); + for (event = ISC_LIST_HEAD(ctx->on_run); event != NULL; event = next_event) { next_event = ISC_LIST_NEXT(event, ev_link); - ISC_LIST_UNLINK(on_run, event, ev_link); + ISC_LIST_UNLINK(ctx->on_run, event, ev_link); task = event->ev_sender; event->ev_sender = NULL; isc_task_sendanddetach(&task, &event); @@ -464,7 +603,7 @@ isc_app_run(void) { } - UNLOCK(&lock); + UNLOCK(&ctx->lock); #ifndef HAVE_SIGWAIT /* @@ -473,19 +612,27 @@ isc_app_run(void) { * We do this here to ensure that the signal handler is installed * (i.e. that it wasn't a "one-shot" handler). */ - result = handle_signal(SIGHUP, reload_action); - if (result != ISC_R_SUCCESS) - return (ISC_R_SUCCESS); + if (ctx == &isc_g_appctx) { + result = handle_signal(SIGHUP, reload_action); + if (result != ISC_R_SUCCESS) + return (ISC_R_SUCCESS); + } #endif -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_THREADS_SINGLECTX + /* + * When we are using multiple contexts, we don't rely on signals. + */ + if (ctx != &isc_g_appctx) + return (ISC_R_SUCCESS); + /* * There is no danger if isc_app_shutdown() is called before we wait * for signals. Signals are blocked, so any such signal will simply * be made pending and we will get it when we call sigwait(). */ - while (!want_shutdown) { + while (!ctx->want_shutdown) { #ifdef HAVE_SIGWAIT /* * Wait for SIGHUP, SIGINT, or SIGTERM. @@ -503,21 +650,19 @@ isc_app_run(void) { #ifndef HAVE_UNIXWARE_SIGWAIT result = sigwait(&sset, &sig); if (result == 0) { - if (sig == SIGINT || - sig == SIGTERM) - want_shutdown = ISC_TRUE; + if (sig == SIGINT || sig == SIGTERM) + ctx->want_shutdown = ISC_TRUE; else if (sig == SIGHUP) - want_reload = ISC_TRUE; + ctx->want_reload = ISC_TRUE; } #else /* Using UnixWare sigwait semantics. */ sig = sigwait(&sset); if (sig >= 0) { - if (sig == SIGINT || - sig == SIGTERM) - want_shutdown = ISC_TRUE; + if (sig == SIGINT || sig == SIGTERM) + ctx->want_shutdown = ISC_TRUE; else if (sig == SIGHUP) - want_reload = ISC_TRUE; + ctx->want_reload = ISC_TRUE; } #endif /* HAVE_UNIXWARE_SIGWAIT */ @@ -528,131 +673,174 @@ isc_app_run(void) { if (sigemptyset(&sset) != 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_app_run() sigsetops: %s", strbuf); + "isc_app_run() sigsetops: %s", + strbuf); return (ISC_R_UNEXPECTED); } result = sigsuspend(&sset); #endif /* HAVE_SIGWAIT */ - if (want_reload) { - want_reload = ISC_FALSE; + if (ctx->want_reload) { + ctx->want_reload = ISC_FALSE; return (ISC_R_RELOAD); } - if (want_shutdown && blocked) + if (ctx->want_shutdown && ctx->blocked) exit(1); } -#else /* ISC_PLATFORM_USETHREADS */ +#else /* USE_THREADS_SINGLECTX */ - (void)isc__taskmgr_dispatch(); + (void)isc__taskmgr_dispatch(ctx->taskmgr); - result = evloop(); + result = evloop(ctx); if (result != ISC_R_SUCCESS) return (result); -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_THREADS_SINGLECTX */ return (ISC_R_SUCCESS); } -isc_result_t -isc_app_shutdown(void) { +ISC_APPFUNC_SCOPE isc_result_t +isc__app_run() { + return (isc__app_ctxrun((isc_appctx_t *)&isc_g_appctx)); +} + +ISC_APPFUNC_SCOPE isc_result_t +isc__app_ctxshutdown(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; isc_boolean_t want_kill = ISC_TRUE; char strbuf[ISC_STRERRORSIZE]; - LOCK(&lock); + REQUIRE(VALID_APPCTX(ctx)); - REQUIRE(running); + LOCK(&ctx->lock); - if (shutdown_requested) + REQUIRE(ctx->running); + + if (ctx->shutdown_requested) want_kill = ISC_FALSE; else - shutdown_requested = ISC_TRUE; + ctx->shutdown_requested = ISC_TRUE; - UNLOCK(&lock); + UNLOCK(&ctx->lock); if (want_kill) { + if (ctx != &isc_g_appctx) + ctx->want_shutdown = ISC_TRUE; + else { #ifdef HAVE_LINUXTHREADS - int result; - - result = pthread_kill(main_thread, SIGTERM); - if (result != 0) { - isc__strerror(result, strbuf, sizeof(strbuf)); - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_app_shutdown() pthread_kill: %s", - strbuf); - return (ISC_R_UNEXPECTED); - } + int result; + + result = pthread_kill(main_thread, SIGTERM); + if (result != 0) { + isc__strerror(result, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_shutdown() " + "pthread_kill: %s", + strbuf); + return (ISC_R_UNEXPECTED); + } #else - if (kill(getpid(), SIGTERM) < 0) { - isc__strerror(errno, strbuf, sizeof(strbuf)); - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_app_shutdown() kill: %s", strbuf); - return (ISC_R_UNEXPECTED); + if (kill(getpid(), SIGTERM) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_shutdown() " + "kill: %s", strbuf); + return (ISC_R_UNEXPECTED); + } +#endif /* HAVE_LINUXTHREADS */ } -#endif } return (ISC_R_SUCCESS); } -isc_result_t -isc_app_reload(void) { +ISC_APPFUNC_SCOPE isc_result_t +isc__app_shutdown() { + return (isc__app_ctxshutdown((isc_appctx_t *)&isc_g_appctx)); +} + +ISC_APPFUNC_SCOPE isc_result_t +isc__app_ctxsuspend(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; isc_boolean_t want_kill = ISC_TRUE; char strbuf[ISC_STRERRORSIZE]; - LOCK(&lock); + REQUIRE(VALID_APPCTX(ctx)); + + LOCK(&ctx->lock); - REQUIRE(running); + REQUIRE(ctx->running); /* * Don't send the reload signal if we're shutting down. */ - if (shutdown_requested) + if (ctx->shutdown_requested) want_kill = ISC_FALSE; - UNLOCK(&lock); + UNLOCK(&ctx->lock); if (want_kill) { + if (ctx != &isc_g_appctx) + ctx->want_reload = ISC_TRUE; + else { #ifdef HAVE_LINUXTHREADS - int result; - - result = pthread_kill(main_thread, SIGHUP); - if (result != 0) { - isc__strerror(result, strbuf, sizeof(strbuf)); - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_app_reload() pthread_kill: %s", - strbuf); - return (ISC_R_UNEXPECTED); - } + int result; + + result = pthread_kill(main_thread, SIGHUP); + if (result != 0) { + isc__strerror(result, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_reload() " + "pthread_kill: %s", + strbuf); + return (ISC_R_UNEXPECTED); + } #else - if (kill(getpid(), SIGHUP) < 0) { - isc__strerror(errno, strbuf, sizeof(strbuf)); - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_app_reload() kill: %s", strbuf); - return (ISC_R_UNEXPECTED); - } + if (kill(getpid(), SIGHUP) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_reload() " + "kill: %s", strbuf); + return (ISC_R_UNEXPECTED); + } #endif + } } return (ISC_R_SUCCESS); } -void -isc_app_finish(void) { - DESTROYLOCK(&lock); +ISC_APPFUNC_SCOPE isc_result_t +isc__app_reload(void) { + return (isc__app_ctxsuspend((isc_appctx_t *)&isc_g_appctx)); +} + +ISC_APPFUNC_SCOPE void +isc__app_ctxfinish(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + + REQUIRE(VALID_APPCTX(ctx)); + + DESTROYLOCK(&ctx->lock); +} + +ISC_APPFUNC_SCOPE void +isc__app_finish(void) { + isc__app_ctxfinish((isc_appctx_t *)&isc_g_appctx); } -void -isc_app_block(void) { +ISC_APPFUNC_SCOPE void +isc__app_block(void) { #ifdef ISC_PLATFORM_USETHREADS sigset_t sset; #endif /* ISC_PLATFORM_USETHREADS */ - REQUIRE(running); - REQUIRE(!blocked); + REQUIRE(isc_g_appctx.running); + REQUIRE(!isc_g_appctx.blocked); - blocked = ISC_TRUE; + isc_g_appctx.blocked = ISC_TRUE; #ifdef ISC_PLATFORM_USETHREADS blockedthread = pthread_self(); RUNTIME_CHECK(sigemptyset(&sset) == 0 && @@ -662,16 +850,16 @@ isc_app_block(void) { #endif /* ISC_PLATFORM_USETHREADS */ } -void -isc_app_unblock(void) { +ISC_APPFUNC_SCOPE void +isc__app_unblock(void) { #ifdef ISC_PLATFORM_USETHREADS sigset_t sset; #endif /* ISC_PLATFORM_USETHREADS */ - REQUIRE(running); - REQUIRE(blocked); + REQUIRE(isc_g_appctx.running); + REQUIRE(isc_g_appctx.blocked); - blocked = ISC_FALSE; + isc_g_appctx.blocked = ISC_FALSE; #ifdef ISC_PLATFORM_USETHREADS REQUIRE(blockedthread == pthread_self()); @@ -682,3 +870,77 @@ isc_app_unblock(void) { RUNTIME_CHECK(pthread_sigmask(SIG_BLOCK, &sset, NULL) == 0); #endif /* ISC_PLATFORM_USETHREADS */ } + +ISC_APPFUNC_SCOPE isc_result_t +isc__appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp) { + isc__appctx_t *ctx; + + REQUIRE(mctx != NULL); + REQUIRE(ctxp != NULL && *ctxp == NULL); + + ctx = isc_mem_get(mctx, sizeof(*ctx)); + if (ctx == NULL) + return (ISC_R_NOMEMORY); + + ctx->common.impmagic = APPCTX_MAGIC; + ctx->common.magic = ISCAPI_APPCTX_MAGIC; + ctx->common.methods = &appmethods.methods; + + ctx->mctx = NULL; + isc_mem_attach(mctx, &ctx->mctx); + + ctx->taskmgr = NULL; + ctx->socketmgr = NULL; + ctx->timermgr = NULL; + + *ctxp = (isc_appctx_t *)ctx; + + return (ISC_R_SUCCESS); +} + +ISC_APPFUNC_SCOPE void +isc__appctx_destroy(isc_appctx_t **ctxp) { + isc__appctx_t *ctx; + + REQUIRE(ctxp != NULL); + ctx = (isc__appctx_t *)*ctxp; + REQUIRE(VALID_APPCTX(ctx)); + + isc_mem_putanddetach(&ctx->mctx, ctx, sizeof(*ctx)); + + *ctxp = NULL; +} + +ISC_APPFUNC_SCOPE void +isc__appctx_settaskmgr(isc_appctx_t *ctx0, isc_taskmgr_t *taskmgr) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + + REQUIRE(VALID_APPCTX(ctx)); + + ctx->taskmgr = taskmgr; +} + +ISC_APPFUNC_SCOPE void +isc__appctx_setsocketmgr(isc_appctx_t *ctx0, isc_socketmgr_t *socketmgr) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + + REQUIRE(VALID_APPCTX(ctx)); + + ctx->socketmgr = socketmgr; +} + +ISC_APPFUNC_SCOPE void +isc__appctx_settimermgr(isc_appctx_t *ctx0, isc_timermgr_t *timermgr) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + + REQUIRE(VALID_APPCTX(ctx)); + + ctx->timermgr = timermgr; +} + +#ifdef USE_APPIMPREGISTER +isc_result_t +isc__app_register() { + return (isc_app_register(isc__appctx_create)); +} +#endif diff --git a/lib/isc/unix/dir.c b/lib/isc/unix/dir.c index 8053c42..0caf882 100644 --- a/lib/isc/unix/dir.c +++ b/lib/isc/unix/dir.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dir.c,v 1.25.332.3 2009-02-16 23:47:15 tbox Exp $ */ +/* $Id: dir.c,v 1.29 2009-02-16 23:48:04 tbox Exp $ */ /*! \file * \author Principal Authors: DCL */ diff --git a/lib/isc/unix/entropy.c b/lib/isc/unix/entropy.c index bdff8d9..9044632 100644 --- a/lib/isc/unix/entropy.c +++ b/lib/isc/unix/entropy.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: entropy.c,v 1.80.332.2 2009-02-16 23:47:15 tbox Exp $ */ +/* $Id: entropy.c,v 1.82 2008-12-01 23:47:45 tbox Exp $ */ /* \file unix/entropy.c * \brief diff --git a/lib/isc/unix/file.c b/lib/isc/unix/file.c index ae737b8..25d856c 100644 --- a/lib/isc/unix/file.c +++ b/lib/isc/unix/file.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -48,7 +48,7 @@ * SUCH DAMAGE. */ -/* $Id: file.c,v 1.51.332.2 2009-02-16 23:47:15 tbox Exp $ */ +/* $Id: file.c,v 1.57 2011-01-11 23:47:14 tbox Exp $ */ /*! \file */ @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -242,16 +243,26 @@ isc_file_renameunique(const char *file, char *templet) { return (ISC_R_SUCCESS); } - isc_result_t isc_file_openunique(char *templet, FILE **fp) { + int mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; + return (isc_file_openuniquemode(templet, mode, fp)); +} + +isc_result_t +isc_file_openuniqueprivate(char *templet, FILE **fp) { + int mode = S_IWUSR|S_IRUSR; + return (isc_file_openuniquemode(templet, mode, fp)); +} + +isc_result_t +isc_file_openuniquemode(char *templet, int mode, FILE **fp) { int fd; FILE *f; isc_result_t result = ISC_R_SUCCESS; char *x; char *cp; isc_uint32_t which; - int mode; REQUIRE(templet != NULL); REQUIRE(fp != NULL && *fp == NULL); @@ -269,7 +280,6 @@ isc_file_openunique(char *templet, FILE **fp) { x = cp--; } - mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; while ((fd = open(templet, O_RDWR|O_CREAT|O_EXCL, mode)) == -1) { if (errno != EEXIST) @@ -442,3 +452,73 @@ isc_file_truncate(const char *filename, isc_offset_t size) { result = isc__errno2result(errno); return (result); } + +isc_result_t +isc_file_safecreate(const char *filename, FILE **fp) { + isc_result_t result; + int flags; + struct stat sb; + FILE *f; + int fd; + + REQUIRE(filename != NULL); + REQUIRE(fp != NULL && *fp == NULL); + + result = file_stats(filename, &sb); + if (result == ISC_R_SUCCESS) { + if ((sb.st_mode & S_IFREG) == 0) + return (ISC_R_INVALIDFILE); + flags = O_WRONLY | O_TRUNC; + } else if (result == ISC_R_FILENOTFOUND) { + flags = O_WRONLY | O_CREAT | O_EXCL; + } else + return (result); + + fd = open(filename, flags, S_IRUSR | S_IWUSR); + if (fd == -1) + return (isc__errno2result(errno)); + + f = fdopen(fd, "w"); + if (f == NULL) { + result = isc__errno2result(errno); + close(fd); + return (result); + } + + *fp = f; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_file_splitpath(isc_mem_t *mctx, char *path, char **dirname, char **basename) +{ + char *dir, *file, *slash; + + slash = strrchr(path, '/'); + + if (slash == path) { + file = ++slash; + dir = isc_mem_strdup(mctx, "/"); + } else if (slash != NULL) { + file = ++slash; + dir = isc_mem_allocate(mctx, slash - path); + if (dir != NULL) + strlcpy(dir, path, slash - path); + } else { + file = path; + dir = isc_mem_strdup(mctx, "."); + } + + if (dir == NULL) + return (ISC_R_NOMEMORY); + + if (*file == '\0') { + isc_mem_free(mctx, dir); + return (ISC_R_INVALIDFILE); + } + + *dirname = dir; + *basename = file; + + return (ISC_R_SUCCESS); +} diff --git a/lib/isc/unix/ifiter_getifaddrs.c b/lib/isc/unix/ifiter_getifaddrs.c index 1e9c814..90a3faf 100644 --- a/lib/isc/unix/ifiter_getifaddrs.c +++ b/lib/isc/unix/ifiter_getifaddrs.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ifiter_getifaddrs.c,v 1.11.120.2 2009-09-24 23:47:34 tbox Exp $ */ +/* $Id: ifiter_getifaddrs.c,v 1.13 2009-09-24 23:48:13 tbox Exp $ */ /*! \file * \brief diff --git a/lib/isc/unix/ifiter_ioctl.c b/lib/isc/unix/ifiter_ioctl.c index c004f61..010b365 100644 --- a/lib/isc/unix/ifiter_ioctl.c +++ b/lib/isc/unix/ifiter_ioctl.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ifiter_ioctl.c,v 1.60.120.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: ifiter_ioctl.c,v 1.62 2009-01-18 23:48:14 tbox Exp $ */ /*! \file * \brief diff --git a/lib/isc/unix/include/isc/net.h b/lib/isc/unix/include/isc/net.h index 5fad793..112f1d7 100644 --- a/lib/isc/unix/include/isc/net.h +++ b/lib/isc/unix/include/isc/net.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: net.h,v 1.48.84.2 2009-02-16 23:47:15 tbox Exp $ */ +/* $Id: net.h,v 1.50 2008-12-01 04:14:54 marka Exp $ */ #ifndef ISC_NET_H #define ISC_NET_H 1 diff --git a/lib/isc/unix/include/isc/offset.h b/lib/isc/unix/include/isc/offset.h index 91f43c37..2920899 100644 --- a/lib/isc/unix/include/isc/offset.h +++ b/lib/isc/unix/include/isc/offset.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: offset.h,v 1.15.332.2 2009-02-16 23:47:15 tbox Exp $ */ +/* $Id: offset.h,v 1.17 2008-12-01 23:47:45 tbox Exp $ */ #ifndef ISC_OFFSET_H #define ISC_OFFSET_H 1 diff --git a/lib/isc/unix/include/isc/strerror.h b/lib/isc/unix/include/isc/strerror.h index e094e96..ac8d496 100644 --- a/lib/isc/unix/include/isc/strerror.h +++ b/lib/isc/unix/include/isc/strerror.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: strerror.h,v 1.8.332.2 2009-02-16 23:47:15 tbox Exp $ */ +/* $Id: strerror.h,v 1.10 2008-12-01 23:47:45 tbox Exp $ */ #ifndef ISC_STRERROR_H #define ISC_STRERROR_H diff --git a/lib/isc/unix/include/isc/time.h b/lib/isc/unix/include/isc/time.h index 2149011..19f0810 100644 --- a/lib/isc/unix/include/isc/time.h +++ b/lib/isc/unix/include/isc/time.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: time.h,v 1.38.56.2 2009-01-05 23:47:23 tbox Exp $ */ +/* $Id: time.h,v 1.40 2009-01-05 23:47:54 tbox Exp $ */ #ifndef ISC_TIME_H #define ISC_TIME_H 1 diff --git a/lib/isc/unix/interfaceiter.c b/lib/isc/unix/interfaceiter.c index 2d60a33..37fc3b1 100644 --- a/lib/isc/unix/interfaceiter.c +++ b/lib/isc/unix/interfaceiter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: interfaceiter.c,v 1.44.120.2 2009-02-16 23:47:15 tbox Exp $ */ +/* $Id: interfaceiter.c,v 1.45 2008-12-01 03:51:47 marka Exp $ */ /*! \file */ diff --git a/lib/isc/unix/resource.c b/lib/isc/unix/resource.c index 1061282..99a4b8c 100644 --- a/lib/isc/unix/resource.c +++ b/lib/isc/unix/resource.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resource.c,v 1.21.66.2 2009-02-13 23:47:39 tbox Exp $ */ +/* $Id: resource.c,v 1.23 2009-02-13 23:48:14 tbox Exp $ */ #include diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index 055e883..ec7487e 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: socket.c,v 1.308.12.17 2010-12-22 03:28:13 marka Exp $ */ +/* $Id: socket.c,v 1.333.14.2.2.1 2011-06-02 23:47:36 tbox Exp $ */ /*! \file */ @@ -76,9 +76,19 @@ #include "errno2result.h" -#ifndef ISC_PLATFORM_USETHREADS +/* See task.c about the following definition: */ +#ifdef BIND9 +#ifdef ISC_PLATFORM_USETHREADS +#define USE_WATCHER_THREAD +#else +#define USE_SHARED_MANAGER +#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* BIND9 */ + +#ifndef USE_WATCHER_THREAD #include "socket_p.h" -#endif /* ISC_PLATFORM_USETHREADS */ +#include "../task_p.h" +#endif /* USE_WATCHER_THREAD */ #if defined(SO_BSDCOMPAT) && defined(__linux__) #include @@ -101,7 +111,7 @@ typedef struct { #define USE_SELECT #endif /* ISC_PLATFORM_HAVEKQUEUE */ -#ifndef ISC_PLATFORM_USETHREADS +#ifndef USE_WATCHER_THREAD #if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) struct isc_socketwait { int nevents; @@ -114,7 +124,7 @@ struct isc_socketwait { int maxfd; }; #endif /* USE_KQUEUE */ -#endif /* !ISC_PLATFORM_USETHREADS */ +#endif /* !USE_WATCHER_THREAD */ /*% * Maximum number of allowable open sockets. This is also the maximum @@ -248,7 +258,7 @@ typedef enum { poll_idle, poll_active, poll_checking } pollstate_t; typedef isc_event_t intev_t; #define SOCKET_MAGIC ISC_MAGIC('I', 'O', 'i', 'o') -#define VALID_SOCKET(t) ISC_MAGIC_VALID(t, SOCKET_MAGIC) +#define VALID_SOCKET(s) ISC_MAGIC_VALID(s, SOCKET_MAGIC) /*! * IPv6 control information. If the socket is an IPv6 socket we want @@ -282,16 +292,21 @@ typedef isc_event_t intev_t; */ #define NRETRIES 10 -struct isc_socket { +typedef struct isc__socket isc__socket_t; +typedef struct isc__socketmgr isc__socketmgr_t; + +#define NEWCONNSOCK(ev) ((isc__socket_t *)(ev)->newsocket) + +struct isc__socket { /* Not locked. */ - unsigned int magic; - isc_socketmgr_t *manager; + isc_socket_t common; + isc__socketmgr_t *manager; isc_mutex_t lock; isc_sockettype_t type; const isc_statscounter_t *statsindex; /* Locked by socket lock. */ - ISC_LINK(isc_socket_t) link; + ISC_LINK(isc__socket_t) link; unsigned int references; int fd; int pf; @@ -339,9 +354,9 @@ struct isc_socket { #define SOCKET_MANAGER_MAGIC ISC_MAGIC('I', 'O', 'm', 'g') #define VALID_MANAGER(m) ISC_MAGIC_VALID(m, SOCKET_MANAGER_MAGIC) -struct isc_socketmgr { +struct isc__socketmgr { /* Not locked. */ - unsigned int magic; + isc_socketmgr_t common; isc_mem_t *mctx; isc_mutex_t lock; isc_mutex_t *fdlock; @@ -370,14 +385,14 @@ struct isc_socketmgr { #endif /* Locked by fdlock. */ - isc_socket_t **fds; + isc__socket_t **fds; int *fdstate; #ifdef USE_DEVPOLL pollinfo_t *fdpollinfo; #endif /* Locked by manager lock. */ - ISC_LIST(isc_socket_t) socklist; + ISC_LIST(isc__socket_t) socklist; #ifdef USE_SELECT fd_set *read_fds; fd_set *read_fds_copy; @@ -386,17 +401,18 @@ struct isc_socketmgr { int maxfd; #endif /* USE_SELECT */ int reserved; /* unlocked */ -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD isc_thread_t watcher; isc_condition_t shutdown_ok; -#else /* ISC_PLATFORM_USETHREADS */ +#else /* USE_WATCHER_THREAD */ unsigned int refs; -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ + int maxudp; }; -#ifndef ISC_PLATFORM_USETHREADS -static isc_socketmgr_t *socketmgr = NULL; -#endif /* ISC_PLATFORM_USETHREADS */ +#ifdef USE_SHARED_MANAGER +static isc__socketmgr_t *socketmgr = NULL; +#endif /* USE_SHARED_MANAGER */ #define CLOSED 0 /* this one must be zero */ #define MANAGED 1 @@ -412,26 +428,165 @@ static isc_socketmgr_t *socketmgr = NULL; # define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER) #endif -static void send_recvdone_event(isc_socket_t *, isc_socketevent_t **); -static void send_senddone_event(isc_socket_t *, isc_socketevent_t **); -static void free_socket(isc_socket_t **); -static isc_result_t allocate_socket(isc_socketmgr_t *, isc_sockettype_t, - isc_socket_t **); -static void destroy(isc_socket_t **); +static void send_recvdone_event(isc__socket_t *, isc_socketevent_t **); +static void send_senddone_event(isc__socket_t *, isc_socketevent_t **); +static void free_socket(isc__socket_t **); +static isc_result_t allocate_socket(isc__socketmgr_t *, isc_sockettype_t, + isc__socket_t **); +static void destroy(isc__socket_t **); static void internal_accept(isc_task_t *, isc_event_t *); static void internal_connect(isc_task_t *, isc_event_t *); static void internal_recv(isc_task_t *, isc_event_t *); static void internal_send(isc_task_t *, isc_event_t *); static void internal_fdwatch_write(isc_task_t *, isc_event_t *); static void internal_fdwatch_read(isc_task_t *, isc_event_t *); -static void process_cmsg(isc_socket_t *, struct msghdr *, isc_socketevent_t *); -static void build_msghdr_send(isc_socket_t *, isc_socketevent_t *, +static void process_cmsg(isc__socket_t *, struct msghdr *, isc_socketevent_t *); +static void build_msghdr_send(isc__socket_t *, isc_socketevent_t *, struct msghdr *, struct iovec *, size_t *); -static void build_msghdr_recv(isc_socket_t *, isc_socketevent_t *, +static void build_msghdr_recv(isc__socket_t *, isc_socketevent_t *, struct msghdr *, struct iovec *, size_t *); -#ifdef ISC_PLATFORM_USETHREADS -static isc_boolean_t process_ctlfd(isc_socketmgr_t *manager); +#ifdef USE_WATCHER_THREAD +static isc_boolean_t process_ctlfd(isc__socketmgr_t *manager); +#endif + +/*% + * The following can be either static or public, depending on build environment. + */ + +#ifdef BIND9 +#define ISC_SOCKETFUNC_SCOPE +#else +#define ISC_SOCKETFUNC_SCOPE static +#endif + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, + isc_socket_t **socketp); +ISC_SOCKETFUNC_SCOPE void +isc__socket_attach(isc_socket_t *sock, isc_socket_t **socketp); +ISC_SOCKETFUNC_SCOPE void +isc__socket_detach(isc_socket_t **socketp); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, + unsigned int maxsocks); +ISC_SOCKETFUNC_SCOPE void +isc__socketmgr_destroy(isc_socketmgr_t **managerp); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist, + unsigned int minimum, isc_task_t *task, + isc_taskaction_t action, const void *arg); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_recv(isc_socket_t *sock, isc_region_t *region, + unsigned int minimum, isc_task_t *task, + isc_taskaction_t action, const void *arg); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_recv2(isc_socket_t *sock, isc_region_t *region, + unsigned int minimum, isc_task_t *task, + isc_socketevent_t *event, unsigned int flags); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_send(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, const void *arg); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendto(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendto2(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, + isc_socketevent_t *event, unsigned int flags); +ISC_SOCKETFUNC_SCOPE void +isc__socket_cleanunix(isc_sockaddr_t *sockaddr, isc_boolean_t active); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_permunix(isc_sockaddr_t *sockaddr, isc_uint32_t perm, + isc_uint32_t owner, isc_uint32_t group); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr, + unsigned int options); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_filter(isc_socket_t *sock, const char *filter); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_listen(isc_socket_t *sock, unsigned int backlog); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_accept(isc_socket_t *sock, + isc_task_t *task, isc_taskaction_t action, const void *arg); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, + isc_task_t *task, isc_taskaction_t action, + const void *arg); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp); +ISC_SOCKETFUNC_SCOPE void +isc__socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how); +ISC_SOCKETFUNC_SCOPE isc_sockettype_t +isc__socket_gettype(isc_socket_t *sock); +ISC_SOCKETFUNC_SCOPE isc_boolean_t +isc__socket_isbound(isc_socket_t *sock); +ISC_SOCKETFUNC_SCOPE void +isc__socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes); +#if defined(HAVE_LIBXML2) && defined(BIND9) +ISC_SOCKETFUNC_SCOPE void +isc__socketmgr_renderxml(isc_socketmgr_t *mgr0, xmlTextWriterPtr writer); +#endif + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags, + isc_sockfdwatch_t callback, void *cbarg, + isc_task_t *task, isc_socket_t **socketp); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_fdwatchpoke(isc_socket_t *sock, int flags); + +static struct { + isc_socketmethods_t methods; + + /*% + * The following are defined just for avoiding unused static functions. + */ +#ifndef BIND9 + void *recvv, *send, *sendv, *sendto2, *cleanunix, *permunix, *filter, + *listen, *accept, *getpeername, *isbound; +#endif +} socketmethods = { + { + isc__socket_attach, + isc__socket_detach, + isc__socket_bind, + isc__socket_sendto, + isc__socket_connect, + isc__socket_recv, + isc__socket_cancel, + isc__socket_getsockname, + isc__socket_gettype, + isc__socket_ipv6only, + isc__socket_fdwatchpoke + } +#ifndef BIND9 + , + (void *)isc__socket_recvv, (void *)isc__socket_send, + (void *)isc__socket_sendv, (void *)isc__socket_sendto2, + (void *)isc__socket_cleanunix, (void *)isc__socket_permunix, + (void *)isc__socket_filter, (void *)isc__socket_listen, + (void *)isc__socket_accept, (void *)isc__socket_getpeername, + (void *)isc__socket_isbound #endif +}; + +static isc_socketmgrmethods_t socketmgrmethods = { + isc__socketmgr_destroy, + isc__socket_create, + isc__socket_fdwatchcreate +}; #define SELECT_POKE_SHUTDOWN (-1) #define SELECT_POKE_NOTHING (-2) @@ -531,12 +686,14 @@ static const isc_statscounter_t fdwatchstatsindex[] = { isc_sockstatscounter_fdwatchrecvfail }; +#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) || \ + defined(USE_WATCHER_THREAD) static void -manager_log(isc_socketmgr_t *sockmgr, +manager_log(isc__socketmgr_t *sockmgr, isc_logcategory_t *category, isc_logmodule_t *module, int level, const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6); static void -manager_log(isc_socketmgr_t *sockmgr, +manager_log(isc__socketmgr_t *sockmgr, isc_logcategory_t *category, isc_logmodule_t *module, int level, const char *fmt, ...) { @@ -553,14 +710,15 @@ manager_log(isc_socketmgr_t *sockmgr, isc_log_write(isc_lctx, category, module, level, "sockmgr %p: %s", sockmgr, msgbuf); } +#endif static void -socket_log(isc_socket_t *sock, isc_sockaddr_t *address, +socket_log(isc__socket_t *sock, isc_sockaddr_t *address, isc_logcategory_t *category, isc_logmodule_t *module, int level, isc_msgcat_t *msgcat, int msgset, int message, const char *fmt, ...) ISC_FORMAT_PRINTF(9, 10); static void -socket_log(isc_socket_t *sock, isc_sockaddr_t *address, +socket_log(isc__socket_t *sock, isc_sockaddr_t *address, isc_logcategory_t *category, isc_logmodule_t *module, int level, isc_msgcat_t *msgcat, int msgset, int message, const char *fmt, ...) @@ -595,7 +753,7 @@ socket_log(isc_socket_t *sock, isc_sockaddr_t *address, * setting IPV6_V6ONLY. */ static void -FIX_IPV6_RECVPKTINFO(isc_socket_t *sock) +FIX_IPV6_RECVPKTINFO(isc__socket_t *sock) { char strbuf[ISC_STRERRORSIZE]; int on = 1; @@ -632,7 +790,7 @@ inc_stats(isc_stats_t *stats, isc_statscounter_t counterid) { } static inline isc_result_t -watch_fd(isc_socketmgr_t *manager, int fd, int msg) { +watch_fd(isc__socketmgr_t *manager, int fd, int msg) { isc_result_t result = ISC_R_SUCCESS; #ifdef USE_KQUEUE @@ -700,7 +858,7 @@ watch_fd(isc_socketmgr_t *manager, int fd, int msg) { } static inline isc_result_t -unwatch_fd(isc_socketmgr_t *manager, int fd, int msg) { +unwatch_fd(isc__socketmgr_t *manager, int fd, int msg) { isc_result_t result = ISC_R_SUCCESS; #ifdef USE_KQUEUE @@ -787,7 +945,7 @@ unwatch_fd(isc_socketmgr_t *manager, int fd, int msg) { } static void -wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) { +wakeup_socket(isc__socketmgr_t *manager, int fd, int msg) { isc_result_t result; int lockid = FDLOCK_ID(fd); @@ -848,14 +1006,14 @@ wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) { } } -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD /* * Poke the select loop when there is something for us to do. * The write is required (by POSIX) to complete. That is, we * will not get partial writes. */ static void -select_poke(isc_socketmgr_t *mgr, int fd, int msg) { +select_poke(isc__socketmgr_t *mgr, int fd, int msg) { int cc; int buf[2]; char strbuf[ISC_STRERRORSIZE]; @@ -894,7 +1052,7 @@ select_poke(isc_socketmgr_t *mgr, int fd, int msg) { * Read a message on the internal fd. */ static void -select_readmsg(isc_socketmgr_t *mgr, int *fd, int *msg) { +select_readmsg(isc__socketmgr_t *mgr, int *fd, int *msg) { int buf[2]; int cc; char strbuf[ISC_STRERRORSIZE]; @@ -921,19 +1079,19 @@ select_readmsg(isc_socketmgr_t *mgr, int *fd, int *msg) { *fd = buf[0]; *msg = buf[1]; } -#else /* ISC_PLATFORM_USETHREADS */ +#else /* USE_WATCHER_THREAD */ /* * Update the state of the socketmgr when something changes. */ static void -select_poke(isc_socketmgr_t *manager, int fd, int msg) { +select_poke(isc__socketmgr_t *manager, int fd, int msg) { if (msg == SELECT_POKE_SHUTDOWN) return; else if (fd >= 0) wakeup_socket(manager, fd, msg); return; } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ /* * Make a fd non-blocking. @@ -1026,7 +1184,7 @@ cmsg_space(ISC_SOCKADDR_LEN_T len) { * Process control messages received on a socket. */ static void -process_cmsg(isc_socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) { +process_cmsg(isc__socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) { #ifdef USE_CMSG struct cmsghdr *cmsgp; #ifdef ISC_PLATFORM_HAVEIN6PKTINFO @@ -1129,7 +1287,7 @@ process_cmsg(isc_socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) { * this transaction can send. */ static void -build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev, +build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, struct msghdr *msg, struct iovec *iov, size_t *write_countp) { unsigned int iovcount; @@ -1248,7 +1406,7 @@ build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev, * this transaction can receive. */ static void -build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev, +build_msghdr_recv(isc__socket_t *sock, isc_socketevent_t *dev, struct msghdr *msg, struct iovec *iov, size_t *read_countp) { unsigned int iovcount; @@ -1369,7 +1527,7 @@ build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev, } static void -set_dev_address(isc_sockaddr_t *address, isc_socket_t *sock, +set_dev_address(isc_sockaddr_t *address, isc__socket_t *sock, isc_socketevent_t *dev) { if (sock->type == isc_sockettype_udp) { @@ -1393,7 +1551,7 @@ destroy_socketevent(isc_event_t *event) { } static isc_socketevent_t * -allocate_socketevent(isc_socket_t *sock, isc_eventtype_t eventtype, +allocate_socketevent(isc__socket_t *sock, isc_eventtype_t eventtype, isc_taskaction_t action, const void *arg) { isc_socketevent_t *ev; @@ -1446,7 +1604,7 @@ dump_msg(struct msghdr *msg) { #define DOIO_EOF 3 /* EOF, no event sent */ static int -doio_recv(isc_socket_t *sock, isc_socketevent_t *dev) { +doio_recv(isc__socket_t *sock, isc_socketevent_t *dev) { int cc; struct iovec iov[MAXSCATTERGATHER_RECV]; size_t read_count; @@ -1554,6 +1712,12 @@ doio_recv(isc_socket_t *sock, isc_socketevent_t *dev) { } return (DOIO_SOFT); } + /* + * Simulate a firewall blocking UDP responses bigger than + * 512 bytes. + */ + if (sock->manager->maxudp != 0 && cc > sock->manager->maxudp) + return (DOIO_SOFT); } socket_log(sock, &dev->address, IOEVENT, @@ -1630,7 +1794,7 @@ doio_recv(isc_socket_t *sock, isc_socketevent_t *dev) { * No other return values are possible. */ static int -doio_send(isc_socket_t *sock, isc_socketevent_t *dev) { +doio_send(isc__socket_t *sock, isc_socketevent_t *dev) { int cc; struct iovec iov[MAXSCATTERGATHER_SEND]; size_t write_count; @@ -1741,7 +1905,7 @@ doio_send(isc_socket_t *sock, isc_socketevent_t *dev) { * references exist. */ static void -closesocket(isc_socketmgr_t *manager, isc_socket_t *sock, int fd) { +closesocket(isc__socketmgr_t *manager, isc__socket_t *sock, int fd) { isc_sockettype_t type = sock->type; int lockid = FDLOCK_ID(fd); @@ -1804,10 +1968,10 @@ closesocket(isc_socketmgr_t *manager, isc_socket_t *sock, int fd) { } static void -destroy(isc_socket_t **sockp) { +destroy(isc__socket_t **sockp) { int fd; - isc_socket_t *sock = *sockp; - isc_socketmgr_t *manager = sock->manager; + isc__socket_t *sock = *sockp; + isc__socketmgr_t *manager = sock->manager; socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_DESTROYING, "destroying"); @@ -1828,10 +1992,10 @@ destroy(isc_socket_t **sockp) { ISC_LIST_UNLINK(manager->socklist, sock, link); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD if (ISC_LIST_EMPTY(manager->socklist)) SIGNAL(&manager->shutdown_ok); -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ UNLOCK(&manager->lock); @@ -1839,10 +2003,10 @@ destroy(isc_socket_t **sockp) { } static isc_result_t -allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, - isc_socket_t **socketp) +allocate_socket(isc__socketmgr_t *manager, isc_sockettype_t type, + isc__socket_t **socketp) { - isc_socket_t *sock; + isc__socket_t *sock; isc_result_t result; ISC_SOCKADDR_LEN_T cmsgbuflen; @@ -1853,7 +2017,8 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, result = ISC_R_UNEXPECTED; - sock->magic = 0; + sock->common.magic = 0; + sock->common.impmagic = 0; sock->references = 0; sock->manager = manager; @@ -1917,7 +2082,8 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, */ result = isc_mutex_init(&sock->lock); if (result != ISC_R_SUCCESS) { - sock->magic = 0; + sock->common.magic = 0; + sock->common.impmagic = 0; goto error; } @@ -1931,7 +2097,8 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTW, NULL, sock, sock, NULL, NULL); - sock->magic = SOCKET_MAGIC; + sock->common.magic = ISCAPI_SOCKET_MAGIC; + sock->common.impmagic = SOCKET_MAGIC; *socketp = sock; return (ISC_R_SUCCESS); @@ -1956,8 +2123,8 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, * also close the socket. */ static void -free_socket(isc_socket_t **socketp) { - isc_socket_t *sock = *socketp; +free_socket(isc__socket_t **socketp) { + isc__socket_t *sock = *socketp; INSIST(sock->references == 0); INSIST(VALID_SOCKET(sock)); @@ -1977,7 +2144,8 @@ free_socket(isc_socket_t **socketp) { isc_mem_put(sock->manager->mctx, sock->sendcmsgbuf, sock->sendcmsgbuflen); - sock->magic = 0; + sock->common.magic = 0; + sock->common.impmagic = 0; DESTROYLOCK(&sock->lock); @@ -2025,7 +2193,7 @@ clear_bsdcompat(void) { #endif static isc_result_t -opensocket(isc_socketmgr_t *manager, isc_socket_t *sock) { +opensocket(isc__socketmgr_t *manager, isc__socket_t *sock) { char strbuf[ISC_STRERRORSIZE]; const char *err = "socket"; int tries = 0; @@ -2316,11 +2484,12 @@ opensocket(isc_socketmgr_t *manager, isc_socket_t *sock) { * called with 'arg' as the arg value. The new socket is returned * in 'socketp'. */ -isc_result_t -isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, - isc_socket_t **socketp) +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type, + isc_socket_t **socketp) { - isc_socket_t *sock = NULL; + isc__socket_t *sock = NULL; + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; isc_result_t result; int lockid; @@ -2356,8 +2525,9 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, return (result); } + sock->common.methods = (isc_socketmethods_t *)&socketmethods; sock->references = 1; - *socketp = sock; + *socketp = (isc_socket_t *)sock; /* * Note we don't have to lock the socket like we normally would because @@ -2388,9 +2558,11 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, return (ISC_R_SUCCESS); } -isc_result_t -isc_socket_open(isc_socket_t *sock) { +#ifdef BIND9 +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_open(isc_socket_t *sock0) { isc_result_t result; + isc__socket_t *sock = (isc__socket_t *)sock0; REQUIRE(VALID_SOCKET(sock)); @@ -2430,6 +2602,7 @@ isc_socket_open(isc_socket_t *sock) { return (result); } +#endif /* BIND9 */ /* * Create a new 'type' socket managed by 'manager'. Events @@ -2437,12 +2610,13 @@ isc_socket_open(isc_socket_t *sock) { * called with 'arg' as the arg value. The new socket is returned * in 'socketp'. */ -isc_result_t -isc_socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags, - isc_sockfdwatch_t callback, void *cbarg, - isc_task_t *task, isc_socket_t **socketp) +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_fdwatchcreate(isc_socketmgr_t *manager0, int fd, int flags, + isc_sockfdwatch_t callback, void *cbarg, + isc_task_t *task, isc_socket_t **socketp) { - isc_socket_t *sock = NULL; + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; + isc__socket_t *sock = NULL; isc_result_t result; int lockid; @@ -2460,8 +2634,9 @@ isc_socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags, sock->fdwatchtask = task; sock->statsindex = fdwatchstatsindex; + sock->common.methods = (isc_socketmethods_t *)&socketmethods; sock->references = 1; - *socketp = sock; + *socketp = (isc_socket_t *)sock; /* * Note we don't have to lock the socket like we normally would because @@ -2494,10 +2669,50 @@ isc_socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags, } /* + * Indicate to the manager that it should watch the socket again. + * This can be used to restart watching if the previous event handler + * didn't indicate there was more data to be processed. Primarily + * it is for writing but could be used for reading if desired + */ + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_fdwatchpoke(isc_socket_t *sock0, int flags) +{ + isc__socket_t *sock = (isc__socket_t *)sock0; + + REQUIRE(VALID_SOCKET(sock)); + + /* + * We check both flags first to allow us to get the lock + * once but only if we need it. + */ + + if ((flags & (ISC_SOCKFDWATCH_READ | ISC_SOCKFDWATCH_WRITE)) != 0) { + LOCK(&sock->lock); + if (((flags & ISC_SOCKFDWATCH_READ) != 0) && + !sock->pending_recv) + select_poke(sock->manager, sock->fd, + SELECT_POKE_READ); + if (((flags & ISC_SOCKFDWATCH_WRITE) != 0) && + !sock->pending_send) + select_poke(sock->manager, sock->fd, + SELECT_POKE_WRITE); + UNLOCK(&sock->lock); + } + + socket_log(sock, NULL, TRACE, isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_POKED, "fdwatch-poked flags: %d", flags); + + return (ISC_R_SUCCESS); +} + +/* * Attach to a socket. Caller must explicitly detach when it is done. */ -void -isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) { +ISC_SOCKETFUNC_SCOPE void +isc__socket_attach(isc_socket_t *sock0, isc_socket_t **socketp) { + isc__socket_t *sock = (isc__socket_t *)sock0; + REQUIRE(VALID_SOCKET(sock)); REQUIRE(socketp != NULL && *socketp == NULL); @@ -2505,20 +2720,20 @@ isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) { sock->references++; UNLOCK(&sock->lock); - *socketp = sock; + *socketp = (isc_socket_t *)sock; } /* * Dereference a socket. If this is the last reference to it, clean things * up by destroying the socket. */ -void -isc_socket_detach(isc_socket_t **socketp) { - isc_socket_t *sock; +ISC_SOCKETFUNC_SCOPE void +isc__socket_detach(isc_socket_t **socketp) { + isc__socket_t *sock; isc_boolean_t kill_socket = ISC_FALSE; REQUIRE(socketp != NULL); - sock = *socketp; + sock = (isc__socket_t *)*socketp; REQUIRE(VALID_SOCKET(sock)); LOCK(&sock->lock); @@ -2534,10 +2749,12 @@ isc_socket_detach(isc_socket_t **socketp) { *socketp = NULL; } -isc_result_t -isc_socket_close(isc_socket_t *sock) { +#ifdef BIND9 +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_close(isc_socket_t *sock0) { + isc__socket_t *sock = (isc__socket_t *)sock0; int fd; - isc_socketmgr_t *manager; + isc__socketmgr_t *manager; isc_sockettype_t type; REQUIRE(VALID_SOCKET(sock)); @@ -2575,6 +2792,7 @@ isc_socket_close(isc_socket_t *sock) { return (ISC_R_SUCCESS); } +#endif /* BIND9 */ /* * I/O is possible on a given socket. Schedule an event to this task that @@ -2585,7 +2803,7 @@ isc_socket_close(isc_socket_t *sock) { * The socket and manager must be locked before calling this function. */ static void -dispatch_recv(isc_socket_t *sock) { +dispatch_recv(isc__socket_t *sock) { intev_t *iev; isc_socketevent_t *ev; isc_task_t *sender; @@ -2619,7 +2837,7 @@ dispatch_recv(isc_socket_t *sock) { } static void -dispatch_send(isc_socket_t *sock) { +dispatch_send(isc__socket_t *sock) { intev_t *iev; isc_socketevent_t *ev; isc_task_t *sender; @@ -2656,7 +2874,7 @@ dispatch_send(isc_socket_t *sock) { * Dispatch an internal accept event. */ static void -dispatch_accept(isc_socket_t *sock) { +dispatch_accept(isc__socket_t *sock) { intev_t *iev; isc_socket_newconnev_t *ev; @@ -2682,7 +2900,7 @@ dispatch_accept(isc_socket_t *sock) { } static void -dispatch_connect(isc_socket_t *sock) { +dispatch_connect(isc__socket_t *sock) { intev_t *iev; isc_socket_connev_t *ev; @@ -2712,7 +2930,7 @@ dispatch_connect(isc_socket_t *sock) { * Caller must have the socket locked if the event is attached to the socket. */ static void -send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev) { +send_recvdone_event(isc__socket_t *sock, isc_socketevent_t **dev) { isc_task_t *task; task = (*dev)->ev_sender; @@ -2735,7 +2953,7 @@ send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev) { * Caller must have the socket locked if the event is attached to the socket. */ static void -send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev) { +send_senddone_event(isc__socket_t *sock, isc_socketevent_t **dev) { isc_task_t *task; INSIST(dev != NULL && *dev != NULL); @@ -2766,8 +2984,8 @@ send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev) { */ static void internal_accept(isc_task_t *me, isc_event_t *ev) { - isc_socket_t *sock; - isc_socketmgr_t *manager; + isc__socket_t *sock; + isc__socketmgr_t *manager; isc_socket_newconnev_t *dev; isc_task_t *task; ISC_SOCKADDR_LEN_T addrlen; @@ -2822,9 +3040,9 @@ internal_accept(isc_task_t *me, isc_event_t *ev) { * daemons such as BIND 8 and Apache. */ - addrlen = sizeof(dev->newsocket->peer_address.type); - memset(&dev->newsocket->peer_address.type, 0, addrlen); - fd = accept(sock->fd, &dev->newsocket->peer_address.type.sa, + addrlen = sizeof(NEWCONNSOCK(dev)->peer_address.type); + memset(&NEWCONNSOCK(dev)->peer_address.type, 0, addrlen); + fd = accept(sock->fd, &NEWCONNSOCK(dev)->peer_address.type.sa, (void *)&addrlen); #ifdef F_DUPFD @@ -2894,14 +3112,14 @@ internal_accept(isc_task_t *me, isc_event_t *ev) { (void)close(fd); goto soft_error; - } else if (dev->newsocket->peer_address.type.sa.sa_family != + } else if (NEWCONNSOCK(dev)->peer_address.type.sa.sa_family != sock->pf) { UNEXPECTED_ERROR(__FILE__, __LINE__, "internal_accept(): " "accept() returned peer address " "family %u (expected %u)", - dev->newsocket->peer_address. + NEWCONNSOCK(dev)->peer_address. type.sa.sa_family, sock->pf); (void)close(fd); @@ -2920,8 +3138,8 @@ internal_accept(isc_task_t *me, isc_event_t *ev) { } if (fd != -1) { - dev->newsocket->peer_address.length = addrlen; - dev->newsocket->pf = sock->pf; + NEWCONNSOCK(dev)->peer_address.length = addrlen; + NEWCONNSOCK(dev)->pf = sock->pf; } /* @@ -2950,28 +3168,28 @@ internal_accept(isc_task_t *me, isc_event_t *ev) { int lockid = FDLOCK_ID(fd); LOCK(&manager->fdlock[lockid]); - manager->fds[fd] = dev->newsocket; + manager->fds[fd] = NEWCONNSOCK(dev); manager->fdstate[fd] = MANAGED; UNLOCK(&manager->fdlock[lockid]); LOCK(&manager->lock); - ISC_LIST_APPEND(manager->socklist, dev->newsocket, link); + ISC_LIST_APPEND(manager->socklist, NEWCONNSOCK(dev), link); - dev->newsocket->fd = fd; - dev->newsocket->bound = 1; - dev->newsocket->connected = 1; + NEWCONNSOCK(dev)->fd = fd; + NEWCONNSOCK(dev)->bound = 1; + NEWCONNSOCK(dev)->connected = 1; /* * Save away the remote address */ - dev->address = dev->newsocket->peer_address; + dev->address = NEWCONNSOCK(dev)->peer_address; #ifdef USE_SELECT if (manager->maxfd < fd) manager->maxfd = fd; #endif - socket_log(sock, &dev->newsocket->peer_address, CREATION, + socket_log(sock, &NEWCONNSOCK(dev)->peer_address, CREATION, isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN, "accepted connection, new socket %p", dev->newsocket); @@ -2981,8 +3199,8 @@ internal_accept(isc_task_t *me, isc_event_t *ev) { inc_stats(manager->stats, sock->statsindex[STATID_ACCEPT]); } else { inc_stats(manager->stats, sock->statsindex[STATID_ACCEPTFAIL]); - dev->newsocket->references--; - free_socket(&dev->newsocket); + NEWCONNSOCK(dev)->references--; + free_socket((isc__socket_t **)&dev->newsocket); } /* @@ -3006,7 +3224,7 @@ internal_accept(isc_task_t *me, isc_event_t *ev) { static void internal_recv(isc_task_t *me, isc_event_t *ev) { isc_socketevent_t *dev; - isc_socket_t *sock; + isc__socket_t *sock; INSIST(ev->ev_type == ISC_SOCKEVENT_INTR); @@ -3071,14 +3289,14 @@ internal_recv(isc_task_t *me, isc_event_t *ev) { static void internal_send(isc_task_t *me, isc_event_t *ev) { isc_socketevent_t *dev; - isc_socket_t *sock; + isc__socket_t *sock; INSIST(ev->ev_type == ISC_SOCKEVENT_INTW); /* * Find out what socket this is and lock it. */ - sock = (isc_socket_t *)ev->ev_sender; + sock = (isc__socket_t *)ev->ev_sender; INSIST(VALID_SOCKET(sock)); LOCK(&sock->lock); @@ -3125,7 +3343,7 @@ internal_send(isc_task_t *me, isc_event_t *ev) { static void internal_fdwatch_write(isc_task_t *me, isc_event_t *ev) { - isc_socket_t *sock; + isc__socket_t *sock; int more_data; INSIST(ev->ev_type == ISC_SOCKEVENT_INTW); @@ -3133,7 +3351,7 @@ internal_fdwatch_write(isc_task_t *me, isc_event_t *ev) { /* * Find out what socket this is and lock it. */ - sock = (isc_socket_t *)ev->ev_sender; + sock = (isc__socket_t *)ev->ev_sender; INSIST(VALID_SOCKET(sock)); LOCK(&sock->lock); @@ -3144,7 +3362,8 @@ internal_fdwatch_write(isc_task_t *me, isc_event_t *ev) { INSIST(sock->pending_send == 1); UNLOCK(&sock->lock); - more_data = (sock->fdwatchcb)(me, sock, sock->fdwatcharg); + more_data = (sock->fdwatchcb)(me, (isc_socket_t *)sock, + sock->fdwatcharg, ISC_SOCKFDWATCH_WRITE); LOCK(&sock->lock); sock->pending_send = 0; @@ -3165,7 +3384,7 @@ internal_fdwatch_write(isc_task_t *me, isc_event_t *ev) { static void internal_fdwatch_read(isc_task_t *me, isc_event_t *ev) { - isc_socket_t *sock; + isc__socket_t *sock; int more_data; INSIST(ev->ev_type == ISC_SOCKEVENT_INTR); @@ -3173,7 +3392,7 @@ internal_fdwatch_read(isc_task_t *me, isc_event_t *ev) { /* * Find out what socket this is and lock it. */ - sock = (isc_socket_t *)ev->ev_sender; + sock = (isc__socket_t *)ev->ev_sender; INSIST(VALID_SOCKET(sock)); LOCK(&sock->lock); @@ -3184,7 +3403,8 @@ internal_fdwatch_read(isc_task_t *me, isc_event_t *ev) { INSIST(sock->pending_recv == 1); UNLOCK(&sock->lock); - more_data = (sock->fdwatchcb)(me, sock, sock->fdwatcharg); + more_data = (sock->fdwatchcb)(me, (isc_socket_t *)sock, + sock->fdwatcharg, ISC_SOCKFDWATCH_READ); LOCK(&sock->lock); sock->pending_recv = 0; @@ -3208,10 +3428,10 @@ internal_fdwatch_read(isc_task_t *me, isc_event_t *ev) { * and unlocking twice if both reads and writes are possible. */ static void -process_fd(isc_socketmgr_t *manager, int fd, isc_boolean_t readable, +process_fd(isc__socketmgr_t *manager, int fd, isc_boolean_t readable, isc_boolean_t writeable) { - isc_socket_t *sock; + isc__socket_t *sock; isc_boolean_t unlock_sock; isc_boolean_t unwatch_read = ISC_FALSE, unwatch_write = ISC_FALSE; int lockid = FDLOCK_ID(fd); @@ -3277,11 +3497,11 @@ check_write: #ifdef USE_KQUEUE static isc_boolean_t -process_fds(isc_socketmgr_t *manager, struct kevent *events, int nevents) { +process_fds(isc__socketmgr_t *manager, struct kevent *events, int nevents) { int i; isc_boolean_t readable, writable; isc_boolean_t done = ISC_FALSE; -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD isc_boolean_t have_ctlevent = ISC_FALSE; #endif @@ -3299,7 +3519,7 @@ process_fds(isc_socketmgr_t *manager, struct kevent *events, int nevents) { for (i = 0; i < nevents; i++) { REQUIRE(events[i].ident < manager->maxsocks); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD if (events[i].ident == (uintptr_t)manager->pipe_fds[0]) { have_ctlevent = ISC_TRUE; continue; @@ -3310,7 +3530,7 @@ process_fds(isc_socketmgr_t *manager, struct kevent *events, int nevents) { process_fd(manager, events[i].ident, readable, writable); } -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD if (have_ctlevent) done = process_ctlfd(manager); #endif @@ -3319,10 +3539,11 @@ process_fds(isc_socketmgr_t *manager, struct kevent *events, int nevents) { } #elif defined(USE_EPOLL) static isc_boolean_t -process_fds(isc_socketmgr_t *manager, struct epoll_event *events, int nevents) { +process_fds(isc__socketmgr_t *manager, struct epoll_event *events, int nevents) +{ int i; isc_boolean_t done = ISC_FALSE; -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD isc_boolean_t have_ctlevent = ISC_FALSE; #endif @@ -3335,7 +3556,7 @@ process_fds(isc_socketmgr_t *manager, struct epoll_event *events, int nevents) { for (i = 0; i < nevents; i++) { REQUIRE(events[i].data.fd < (int)manager->maxsocks); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD if (events[i].data.fd == manager->pipe_fds[0]) { have_ctlevent = ISC_TRUE; continue; @@ -3357,7 +3578,7 @@ process_fds(isc_socketmgr_t *manager, struct epoll_event *events, int nevents) { (events[i].events & EPOLLOUT) != 0); } -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD if (have_ctlevent) done = process_ctlfd(manager); #endif @@ -3366,10 +3587,10 @@ process_fds(isc_socketmgr_t *manager, struct epoll_event *events, int nevents) { } #elif defined(USE_DEVPOLL) static isc_boolean_t -process_fds(isc_socketmgr_t *manager, struct pollfd *events, int nevents) { +process_fds(isc__socketmgr_t *manager, struct pollfd *events, int nevents) { int i; isc_boolean_t done = ISC_FALSE; -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD isc_boolean_t have_ctlevent = ISC_FALSE; #endif @@ -3382,7 +3603,7 @@ process_fds(isc_socketmgr_t *manager, struct pollfd *events, int nevents) { for (i = 0; i < nevents; i++) { REQUIRE(events[i].fd < (int)manager->maxsocks); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD if (events[i].fd == manager->pipe_fds[0]) { have_ctlevent = ISC_TRUE; continue; @@ -3393,7 +3614,7 @@ process_fds(isc_socketmgr_t *manager, struct pollfd *events, int nevents) { (events[i].events & POLLOUT) != 0); } -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD if (have_ctlevent) done = process_ctlfd(manager); #endif @@ -3402,27 +3623,27 @@ process_fds(isc_socketmgr_t *manager, struct pollfd *events, int nevents) { } #elif defined(USE_SELECT) static void -process_fds(isc_socketmgr_t *manager, int maxfd, - fd_set *readfds, fd_set *writefds) +process_fds(isc__socketmgr_t *manager, int maxfd, fd_set *readfds, + fd_set *writefds) { int i; REQUIRE(maxfd <= (int)manager->maxsocks); for (i = 0; i < maxfd; i++) { -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD if (i == manager->pipe_fds[0] || i == manager->pipe_fds[1]) continue; -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ process_fd(manager, i, FD_ISSET(i, readfds), FD_ISSET(i, writefds)); } } #endif -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD static isc_boolean_t -process_ctlfd(isc_socketmgr_t *manager) { +process_ctlfd(isc__socketmgr_t *manager) { int msg, fd; for (;;) { @@ -3470,7 +3691,7 @@ process_ctlfd(isc_socketmgr_t *manager) { */ static isc_threadresult_t watcher(void *uap) { - isc_socketmgr_t *manager = uap; + isc__socketmgr_t *manager = uap; isc_boolean_t done; int ctlfd; int cc; @@ -3585,22 +3806,34 @@ watcher(void *uap) { return ((isc_threadresult_t)0); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ -void -isc__socketmgr_setreserved(isc_socketmgr_t *manager, isc_uint32_t reserved) { +#ifdef BIND9 +ISC_SOCKETFUNC_SCOPE void +isc__socketmgr_setreserved(isc_socketmgr_t *manager0, isc_uint32_t reserved) { + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; REQUIRE(VALID_MANAGER(manager)); manager->reserved = reserved; } +ISC_SOCKETFUNC_SCOPE void +isc___socketmgr_maxudp(isc_socketmgr_t *manager0, int maxudp) { + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; + + REQUIRE(VALID_MANAGER(manager)); + + manager->maxudp = maxudp; +} +#endif /* BIND9 */ + /* * Create a new socket manager. */ static isc_result_t -setup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) { +setup_watcher(isc_mem_t *mctx, isc__socketmgr_t *manager) { isc_result_t result; #if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) char strbuf[ISC_STRERRORSIZE]; @@ -3626,7 +3859,7 @@ setup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) { return (result); } -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ); if (result != ISC_R_SUCCESS) { close(manager->kqueue_fd); @@ -3634,7 +3867,7 @@ setup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) { sizeof(struct kevent) * manager->nevents); return (result); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ #elif defined(USE_EPOLL) manager->nevents = ISC_SOCKET_MAXEVENTS; manager->events = isc_mem_get(mctx, sizeof(struct epoll_event) * @@ -3654,7 +3887,7 @@ setup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) { sizeof(struct epoll_event) * manager->nevents); return (result); } -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ); if (result != ISC_R_SUCCESS) { close(manager->epoll_fd); @@ -3662,7 +3895,7 @@ setup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) { sizeof(struct epoll_event) * manager->nevents); return (result); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ #elif defined(USE_DEVPOLL) /* * XXXJT: /dev/poll seems to reject large numbers of events, @@ -3700,7 +3933,7 @@ setup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) { sizeof(pollinfo_t) * manager->maxsocks); return (result); } -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ); if (result != ISC_R_SUCCESS) { close(manager->devpoll_fd); @@ -3710,7 +3943,7 @@ setup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) { sizeof(pollinfo_t) * manager->maxsocks); return (result); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ #elif defined(USE_SELECT) UNUSED(result); @@ -3758,20 +3991,20 @@ setup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) { memset(manager->read_fds, 0, manager->fd_bufsize); memset(manager->write_fds, 0, manager->fd_bufsize); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD (void)watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ); manager->maxfd = manager->pipe_fds[0]; -#else /* ISC_PLATFORM_USETHREADS */ +#else /* USE_WATCHER_THREAD */ manager->maxfd = 0; -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ #endif /* USE_KQUEUE */ return (ISC_R_SUCCESS); } static void -cleanup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) { -#ifdef ISC_PLATFORM_USETHREADS +cleanup_watcher(isc_mem_t *mctx, isc__socketmgr_t *manager) { +#ifdef USE_WATCHER_THREAD isc_result_t result; result = unwatch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ); @@ -3781,7 +4014,7 @@ cleanup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) { isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ #ifdef USE_KQUEUE close(manager->kqueue_fd); @@ -3809,35 +4042,35 @@ cleanup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) { #endif /* USE_KQUEUE */ } -isc_result_t -isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) { - return (isc_socketmgr_create2(mctx, managerp, 0)); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) { + return (isc__socketmgr_create2(mctx, managerp, 0)); } -isc_result_t -isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, - unsigned int maxsocks) +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, + unsigned int maxsocks) { int i; - isc_socketmgr_t *manager; -#ifdef ISC_PLATFORM_USETHREADS + isc__socketmgr_t *manager; +#ifdef USE_WATCHER_THREAD char strbuf[ISC_STRERRORSIZE]; #endif isc_result_t result; REQUIRE(managerp != NULL && *managerp == NULL); -#ifndef ISC_PLATFORM_USETHREADS +#ifdef USE_SHARED_MANAGER if (socketmgr != NULL) { /* Don't allow maxsocks to be updated */ if (maxsocks > 0 && socketmgr->maxsocks != maxsocks) return (ISC_R_EXISTS); socketmgr->refs++; - *managerp = socketmgr; + *managerp = (isc_socketmgr_t *)socketmgr; return (ISC_R_SUCCESS); } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_SHARED_MANAGER */ if (maxsocks == 0) maxsocks = ISC_SOCKET_MAXSOCKETS; @@ -3850,8 +4083,9 @@ isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, memset(manager, 0, sizeof(*manager)); manager->maxsocks = maxsocks; manager->reserved = 0; + manager->maxudp = 0; manager->fds = isc_mem_get(mctx, - manager->maxsocks * sizeof(isc_socket_t *)); + manager->maxsocks * sizeof(isc__socket_t *)); if (manager->fds == NULL) { result = ISC_R_NOMEMORY; goto free_manager; @@ -3863,7 +4097,9 @@ isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, } manager->stats = NULL; - manager->magic = SOCKET_MANAGER_MAGIC; + manager->common.methods = &socketmgrmethods; + manager->common.magic = ISCAPI_SOCKETMGR_MAGIC; + manager->common.impmagic = SOCKET_MANAGER_MAGIC; manager->mctx = NULL; memset(manager->fds, 0, manager->maxsocks * sizeof(isc_socket_t *)); ISC_LIST_INIT(manager->socklist); @@ -3887,7 +4123,7 @@ isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, } } -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_condition_init() %s", @@ -3916,9 +4152,11 @@ isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, #if 0 RUNTIME_CHECK(make_nonblock(manager->pipe_fds[1]) == ISC_R_SUCCESS); #endif -#else /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ + +#ifdef USE_SHARED_MANAGER manager->refs = 1; -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_SHARED_MANAGER */ /* * Set up initial state for the select loop @@ -3927,7 +4165,7 @@ isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, if (result != ISC_R_SUCCESS) goto cleanup; memset(manager->fdstate, 0, manager->maxsocks * sizeof(int)); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD /* * Start up the select/poll thread. */ @@ -3941,26 +4179,26 @@ isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, result = ISC_R_UNEXPECTED; goto cleanup; } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ isc_mem_attach(mctx, &manager->mctx); -#ifndef ISC_PLATFORM_USETHREADS +#ifdef USE_SHARED_MANAGER socketmgr = manager; -#endif /* ISC_PLATFORM_USETHREADS */ - *managerp = manager; +#endif /* USE_SHARED_MANAGER */ + *managerp = (isc_socketmgr_t *)manager; return (ISC_R_SUCCESS); cleanup: -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD (void)close(manager->pipe_fds[0]); (void)close(manager->pipe_fds[1]); -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD cleanup_condition: (void)isc_condition_destroy(&manager->shutdown_ok); -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ cleanup_lock: @@ -3988,8 +4226,10 @@ free_manager: return (result); } +#ifdef BIND9 isc_result_t -isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp) { +isc__socketmgr_getmaxsockets(isc_socketmgr_t *manager0, unsigned int *nsockp) { + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; REQUIRE(VALID_MANAGER(manager)); REQUIRE(nsockp != NULL); @@ -3999,7 +4239,9 @@ isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp) { } void -isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats) { +isc__socketmgr_setstats(isc_socketmgr_t *manager0, isc_stats_t *stats) { + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; + REQUIRE(VALID_MANAGER(manager)); REQUIRE(ISC_LIST_EMPTY(manager->socklist)); REQUIRE(manager->stats == NULL); @@ -4007,10 +4249,11 @@ isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats) { isc_stats_attach(stats, &manager->stats); } +#endif -void -isc_socketmgr_destroy(isc_socketmgr_t **managerp) { - isc_socketmgr_t *manager; +ISC_SOCKETFUNC_SCOPE void +isc__socketmgr_destroy(isc_socketmgr_t **managerp) { + isc__socketmgr_t *manager; int i; isc_mem_t *mctx; @@ -4019,42 +4262,36 @@ isc_socketmgr_destroy(isc_socketmgr_t **managerp) { */ REQUIRE(managerp != NULL); - manager = *managerp; + manager = (isc__socketmgr_t *)*managerp; REQUIRE(VALID_MANAGER(manager)); -#ifndef ISC_PLATFORM_USETHREADS - if (manager->refs > 1) { - manager->refs--; +#ifdef USE_SHARED_MANAGER + manager->refs--; + if (manager->refs > 0) { *managerp = NULL; return; } -#endif /* ISC_PLATFORM_USETHREADS */ + socketmgr = NULL; +#endif /* USE_SHARED_MANAGER */ LOCK(&manager->lock); -#ifdef ISC_PLATFORM_USETHREADS /* * Wait for all sockets to be destroyed. */ while (!ISC_LIST_EMPTY(manager->socklist)) { +#ifdef USE_WATCHER_THREAD manager_log(manager, CREATION, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_SOCKETSREMAIN, "sockets exist")); WAIT(&manager->shutdown_ok, &manager->lock); +#else /* USE_WATCHER_THREAD */ + UNLOCK(&manager->lock); + isc__taskmgr_dispatch(NULL); + LOCK(&manager->lock); +#endif /* USE_WATCHER_THREAD */ } -#else /* ISC_PLATFORM_USETHREADS */ - /* - * Hope all sockets have been destroyed. - */ - if (!ISC_LIST_EMPTY(manager->socklist)) { - manager_log(manager, CREATION, "%s", - isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET, - ISC_MSG_SOCKETSREMAIN, - "sockets exist")); - INSIST(0); - } -#endif /* ISC_PLATFORM_USETHREADS */ UNLOCK(&manager->lock); @@ -4065,7 +4302,7 @@ isc_socketmgr_destroy(isc_socketmgr_t **managerp) { */ select_poke(manager, 0, SELECT_POKE_SHUTDOWN); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD /* * Wait for thread to exit. */ @@ -4074,25 +4311,25 @@ isc_socketmgr_destroy(isc_socketmgr_t **managerp) { "isc_thread_join() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ /* * Clean up. */ cleanup_watcher(manager->mctx, manager); -#ifdef ISC_PLATFORM_USETHREADS +#ifdef USE_WATCHER_THREAD (void)close(manager->pipe_fds[0]); (void)close(manager->pipe_fds[1]); (void)isc_condition_destroy(&manager->shutdown_ok); -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ for (i = 0; i < (int)manager->maxsocks; i++) if (manager->fdstate[i] == CLOSE_PENDING) /* no need to lock */ (void)close(i); isc_mem_put(manager->mctx, manager->fds, - manager->maxsocks * sizeof(isc_socket_t *)); + manager->maxsocks * sizeof(isc__socket_t *)); isc_mem_put(manager->mctx, manager->fdstate, manager->maxsocks * sizeof(int)); @@ -4106,17 +4343,22 @@ isc_socketmgr_destroy(isc_socketmgr_t **managerp) { FDLOCK_COUNT * sizeof(isc_mutex_t)); } DESTROYLOCK(&manager->lock); - manager->magic = 0; + manager->common.magic = 0; + manager->common.impmagic = 0; mctx= manager->mctx; isc_mem_put(mctx, manager, sizeof(*manager)); isc_mem_detach(&mctx); *managerp = NULL; + +#ifdef USE_SHARED_MANAGER + socketmgr = NULL; +#endif } static isc_result_t -socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, +socket_recv(isc__socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, unsigned int flags) { int io_state; @@ -4187,13 +4429,14 @@ socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, return (result); } -isc_result_t -isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist, - unsigned int minimum, isc_task_t *task, - isc_taskaction_t action, const void *arg) +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_recvv(isc_socket_t *sock0, isc_bufferlist_t *buflist, + unsigned int minimum, isc_task_t *task, + isc_taskaction_t action, const void *arg) { + isc__socket_t *sock = (isc__socket_t *)sock0; isc_socketevent_t *dev; - isc_socketmgr_t *manager; + isc__socketmgr_t *manager; unsigned int iocount; isc_buffer_t *buffer; @@ -4241,12 +4484,14 @@ isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist, return (socket_recv(sock, dev, task, 0)); } -isc_result_t -isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum, - isc_task_t *task, isc_taskaction_t action, const void *arg) +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_recv(isc_socket_t *sock0, isc_region_t *region, + unsigned int minimum, isc_task_t *task, + isc_taskaction_t action, const void *arg) { + isc__socket_t *sock = (isc__socket_t *)sock0; isc_socketevent_t *dev; - isc_socketmgr_t *manager; + isc__socketmgr_t *manager; REQUIRE(VALID_SOCKET(sock)); REQUIRE(action != NULL); @@ -4260,14 +4505,16 @@ isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum, if (dev == NULL) return (ISC_R_NOMEMORY); - return (isc_socket_recv2(sock, region, minimum, task, dev, 0)); + return (isc__socket_recv2(sock0, region, minimum, task, dev, 0)); } -isc_result_t -isc_socket_recv2(isc_socket_t *sock, isc_region_t *region, - unsigned int minimum, isc_task_t *task, - isc_socketevent_t *event, unsigned int flags) +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_recv2(isc_socket_t *sock0, isc_region_t *region, + unsigned int minimum, isc_task_t *task, + isc_socketevent_t *event, unsigned int flags) { + isc__socket_t *sock = (isc__socket_t *)sock0; + event->ev_sender = sock; event->result = ISC_R_UNEXPECTED; ISC_LIST_INIT(event->bufferlist); @@ -4292,7 +4539,7 @@ isc_socket_recv2(isc_socket_t *sock, isc_region_t *region, } static isc_result_t -socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, +socket_send(isc__socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, unsigned int flags) { @@ -4383,24 +4630,25 @@ socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, return (result); } -isc_result_t -isc_socket_send(isc_socket_t *sock, isc_region_t *region, - isc_task_t *task, isc_taskaction_t action, const void *arg) +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_send(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, const void *arg) { /* * REQUIRE() checking is performed in isc_socket_sendto(). */ - return (isc_socket_sendto(sock, region, task, action, arg, NULL, - NULL)); + return (isc__socket_sendto(sock, region, task, action, arg, NULL, + NULL)); } -isc_result_t -isc_socket_sendto(isc_socket_t *sock, isc_region_t *region, - isc_task_t *task, isc_taskaction_t action, const void *arg, - isc_sockaddr_t *address, struct in6_pktinfo *pktinfo) +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendto(isc_socket_t *sock0, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo) { + isc__socket_t *sock = (isc__socket_t *)sock0; isc_socketevent_t *dev; - isc_socketmgr_t *manager; + isc__socketmgr_t *manager; REQUIRE(VALID_SOCKET(sock)); REQUIRE(region != NULL); @@ -4422,21 +4670,22 @@ isc_socket_sendto(isc_socket_t *sock, isc_region_t *region, return (socket_send(sock, dev, task, address, pktinfo, 0)); } -isc_result_t -isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist, - isc_task_t *task, isc_taskaction_t action, const void *arg) +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg) { - return (isc_socket_sendtov(sock, buflist, task, action, arg, NULL, - NULL)); + return (isc__socket_sendtov(sock, buflist, task, action, arg, NULL, + NULL)); } -isc_result_t -isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist, - isc_task_t *task, isc_taskaction_t action, const void *arg, - isc_sockaddr_t *address, struct in6_pktinfo *pktinfo) +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendtov(isc_socket_t *sock0, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo) { + isc__socket_t *sock = (isc__socket_t *)sock0; isc_socketevent_t *dev; - isc_socketmgr_t *manager; + isc__socketmgr_t *manager; unsigned int iocount; isc_buffer_t *buffer; @@ -4470,12 +4719,15 @@ isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist, return (socket_send(sock, dev, task, address, pktinfo, 0)); } -isc_result_t -isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region, - isc_task_t *task, - isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, - isc_socketevent_t *event, unsigned int flags) +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendto2(isc_socket_t *sock0, isc_region_t *region, + isc_task_t *task, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, + isc_socketevent_t *event, unsigned int flags) { + isc__socket_t *sock = (isc__socket_t *)sock0; + + REQUIRE(VALID_SOCKET(sock)); REQUIRE((flags & ~(ISC_SOCKFLAG_IMMEDIATE|ISC_SOCKFLAG_NORETRY)) == 0); if ((flags & ISC_SOCKFLAG_NORETRY) != 0) REQUIRE(sock->type == isc_sockettype_udp); @@ -4490,8 +4742,8 @@ isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region, return (socket_send(sock, event, task, address, pktinfo, flags)); } -void -isc_socket_cleanunix(isc_sockaddr_t *sockaddr, isc_boolean_t active) { +ISC_SOCKETFUNC_SCOPE void +isc__socket_cleanunix(isc_sockaddr_t *sockaddr, isc_boolean_t active) { #ifdef ISC_PLATFORM_HAVESYSUNH int s; struct stat sb; @@ -4620,8 +4872,8 @@ isc_socket_cleanunix(isc_sockaddr_t *sockaddr, isc_boolean_t active) { #endif } -isc_result_t -isc_socket_permunix(isc_sockaddr_t *sockaddr, isc_uint32_t perm, +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_permunix(isc_sockaddr_t *sockaddr, isc_uint32_t perm, isc_uint32_t owner, isc_uint32_t group) { #ifdef ISC_PLATFORM_HAVESYSUNH @@ -4674,12 +4926,15 @@ isc_socket_permunix(isc_sockaddr_t *sockaddr, isc_uint32_t perm, #endif } -isc_result_t -isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr, - unsigned int options) { +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_bind(isc_socket_t *sock0, isc_sockaddr_t *sockaddr, + unsigned int options) { + isc__socket_t *sock = (isc__socket_t *)sock0; char strbuf[ISC_STRERRORSIZE]; int on = 1; + REQUIRE(VALID_SOCKET(sock)); + LOCK(&sock->lock); INSIST(!sock->bound); @@ -4745,8 +5000,9 @@ isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr, */ #undef ENABLE_ACCEPTFILTER -isc_result_t -isc_socket_filter(isc_socket_t *sock, const char *filter) { +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_filter(isc_socket_t *sock0, const char *filter) { + isc__socket_t *sock = (isc__socket_t *)sock0; #if defined(SO_ACCEPTFILTER) && defined(ENABLE_ACCEPTFILTER) char strbuf[ISC_STRERRORSIZE]; struct accept_filter_arg afa; @@ -4784,8 +5040,9 @@ isc_socket_filter(isc_socket_t *sock, const char *filter) { * is a new connection we'll have to allocate a new one anyway, so we might * as well keep things simple rather than having to track them. */ -isc_result_t -isc_socket_listen(isc_socket_t *sock, unsigned int backlog) { +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_listen(isc_socket_t *sock0, unsigned int backlog) { + isc__socket_t *sock = (isc__socket_t *)sock0; char strbuf[ISC_STRERRORSIZE]; REQUIRE(VALID_SOCKET(sock)); @@ -4818,14 +5075,15 @@ isc_socket_listen(isc_socket_t *sock, unsigned int backlog) { /* * This should try to do aggressive accept() XXXMLG */ -isc_result_t -isc_socket_accept(isc_socket_t *sock, +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_accept(isc_socket_t *sock0, isc_task_t *task, isc_taskaction_t action, const void *arg) { + isc__socket_t *sock = (isc__socket_t *)sock0; isc_socket_newconnev_t *dev; - isc_socketmgr_t *manager; + isc__socketmgr_t *manager; isc_task_t *ntask = NULL; - isc_socket_t *nsock; + isc__socket_t *nsock; isc_result_t result; isc_boolean_t do_poke = ISC_FALSE; @@ -4872,7 +5130,7 @@ isc_socket_accept(isc_socket_t *sock, nsock->statsindex = sock->statsindex; dev->ev_sender = ntask; - dev->newsocket = nsock; + dev->newsocket = (isc_socket_t *)nsock; /* * Poke watcher here. We still have the socket locked, so there @@ -4891,13 +5149,14 @@ isc_socket_accept(isc_socket_t *sock, return (ISC_R_SUCCESS); } -isc_result_t -isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_connect(isc_socket_t *sock0, isc_sockaddr_t *addr, isc_task_t *task, isc_taskaction_t action, const void *arg) { + isc__socket_t *sock = (isc__socket_t *)sock0; isc_socket_connev_t *dev; isc_task_t *ntask = NULL; - isc_socketmgr_t *manager; + isc__socketmgr_t *manager; int cc; char strbuf[ISC_STRERRORSIZE]; char addrbuf[ISC_SOCKADDR_FORMATSIZE]; @@ -5037,7 +5296,7 @@ isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, */ static void internal_connect(isc_task_t *me, isc_event_t *ev) { - isc_socket_t *sock; + isc__socket_t *sock; isc_socket_connev_t *dev; isc_task_t *task; int cc; @@ -5151,8 +5410,9 @@ internal_connect(isc_task_t *me, isc_event_t *ev) { isc_task_sendanddetach(&task, ISC_EVENT_PTR(&dev)); } -isc_result_t -isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp) { +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_getpeername(isc_socket_t *sock0, isc_sockaddr_t *addressp) { + isc__socket_t *sock = (isc__socket_t *)sock0; isc_result_t result; REQUIRE(VALID_SOCKET(sock)); @@ -5172,8 +5432,9 @@ isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp) { return (result); } -isc_result_t -isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) { +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_getsockname(isc_socket_t *sock0, isc_sockaddr_t *addressp) { + isc__socket_t *sock = (isc__socket_t *)sock0; ISC_SOCKADDR_LEN_T len; isc_result_t result; char strbuf[ISC_STRERRORSIZE]; @@ -5210,8 +5471,9 @@ isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) { * Run through the list of events on this socket, and cancel the ones * queued for task "task" of type "how". "how" is a bitmask. */ -void -isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) { +ISC_SOCKETFUNC_SCOPE void +isc__socket_cancel(isc_socket_t *sock0, isc_task_t *task, unsigned int how) { + isc__socket_t *sock = (isc__socket_t *)sock0; REQUIRE(VALID_SOCKET(sock)); @@ -5290,8 +5552,8 @@ isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) { ISC_LIST_UNLINK(sock->accept_list, dev, ev_link); - dev->newsocket->references--; - free_socket(&dev->newsocket); + NEWCONNSOCK(dev)->references--; + free_socket((isc__socket_t **)&dev->newsocket); dev->result = ISC_R_CANCELED; dev->ev_sender = sock; @@ -5330,17 +5592,22 @@ isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) { UNLOCK(&sock->lock); } -isc_sockettype_t -isc_socket_gettype(isc_socket_t *sock) { +ISC_SOCKETFUNC_SCOPE isc_sockettype_t +isc__socket_gettype(isc_socket_t *sock0) { + isc__socket_t *sock = (isc__socket_t *)sock0; + REQUIRE(VALID_SOCKET(sock)); return (sock->type); } -isc_boolean_t -isc_socket_isbound(isc_socket_t *sock) { +ISC_SOCKETFUNC_SCOPE isc_boolean_t +isc__socket_isbound(isc_socket_t *sock0) { + isc__socket_t *sock = (isc__socket_t *)sock0; isc_boolean_t val; + REQUIRE(VALID_SOCKET(sock)); + LOCK(&sock->lock); val = ((sock->bound) ? ISC_TRUE : ISC_FALSE); UNLOCK(&sock->lock); @@ -5348,8 +5615,9 @@ isc_socket_isbound(isc_socket_t *sock) { return (val); } -void -isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) { +ISC_SOCKETFUNC_SCOPE void +isc__socket_ipv6only(isc_socket_t *sock0, isc_boolean_t yes) { + isc__socket_t *sock = (isc__socket_t *)sock0; #if defined(IPV6_V6ONLY) int onoff = yes ? 1 : 0; #else @@ -5379,12 +5647,21 @@ isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) { #endif } -#ifndef ISC_PLATFORM_USETHREADS -/* In our assumed scenario, we can simply use a single static object. */ +#ifndef USE_WATCHER_THREAD +/* + * In our assumed scenario, we can simply use a single static object. + * XXX: this is not true if the application uses multiple threads with + * 'multi-context' mode. Fixing this is a future TODO item. + */ static isc_socketwait_t swait_private; int -isc__socketmgr_waitevents(struct timeval *tvp, isc_socketwait_t **swaitp) { +isc__socketmgr_waitevents(isc_socketmgr_t *manager0, struct timeval *tvp, + isc_socketwait_t **swaitp) +{ + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; + + int n; #ifdef USE_KQUEUE struct timespec ts, *tsp; @@ -5398,7 +5675,11 @@ isc__socketmgr_waitevents(struct timeval *tvp, isc_socketwait_t **swaitp) { REQUIRE(swaitp != NULL && *swaitp == NULL); - if (socketmgr == NULL) +#ifdef USE_SHARED_MANAGER + if (manager == NULL) + manager = socketmgr; +#endif + if (manager == NULL) return (0); #ifdef USE_KQUEUE @@ -5408,8 +5689,8 @@ isc__socketmgr_waitevents(struct timeval *tvp, isc_socketwait_t **swaitp) { tsp = &ts; } else tsp = NULL; - swait_private.nevents = kevent(socketmgr->kqueue_fd, NULL, 0, - socketmgr->events, socketmgr->nevents, + swait_private.nevents = kevent(manager->kqueue_fd, NULL, 0, + manager->events, manager->nevents, tsp); n = swait_private.nevents; #elif defined(USE_EPOLL) @@ -5417,29 +5698,28 @@ isc__socketmgr_waitevents(struct timeval *tvp, isc_socketwait_t **swaitp) { timeout = tvp->tv_sec * 1000 + (tvp->tv_usec + 999) / 1000; else timeout = -1; - swait_private.nevents = epoll_wait(socketmgr->epoll_fd, - socketmgr->events, - socketmgr->nevents, timeout); + swait_private.nevents = epoll_wait(manager->epoll_fd, + manager->events, + manager->nevents, timeout); n = swait_private.nevents; #elif defined(USE_DEVPOLL) - dvp.dp_fds = socketmgr->events; - dvp.dp_nfds = socketmgr->nevents; + dvp.dp_fds = manager->events; + dvp.dp_nfds = manager->nevents; if (tvp != NULL) { dvp.dp_timeout = tvp->tv_sec * 1000 + (tvp->tv_usec + 999) / 1000; } else dvp.dp_timeout = -1; - swait_private.nevents = ioctl(socketmgr->devpoll_fd, DP_POLL, &dvp); + swait_private.nevents = ioctl(manager->devpoll_fd, DP_POLL, &dvp); n = swait_private.nevents; #elif defined(USE_SELECT) - memcpy(socketmgr->read_fds_copy, socketmgr->read_fds, - socketmgr->fd_bufsize); - memcpy(socketmgr->write_fds_copy, socketmgr->write_fds, - socketmgr->fd_bufsize); + memcpy(manager->read_fds_copy, manager->read_fds, manager->fd_bufsize); + memcpy(manager->write_fds_copy, manager->write_fds, + manager->fd_bufsize); - swait_private.readset = socketmgr->read_fds_copy; - swait_private.writeset = socketmgr->write_fds_copy; - swait_private.maxfd = socketmgr->maxfd + 1; + swait_private.readset = manager->read_fds_copy; + swait_private.writeset = manager->write_fds_copy; + swait_private.maxfd = manager->maxfd + 1; n = select(swait_private.maxfd, swait_private.readset, swait_private.writeset, NULL, tvp); @@ -5450,24 +5730,32 @@ isc__socketmgr_waitevents(struct timeval *tvp, isc_socketwait_t **swaitp) { } isc_result_t -isc__socketmgr_dispatch(isc_socketwait_t *swait) { +isc__socketmgr_dispatch(isc_socketmgr_t *manager0, isc_socketwait_t *swait) { + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; + REQUIRE(swait == &swait_private); - if (socketmgr == NULL) +#ifdef USE_SHARED_MANAGER + if (manager == NULL) + manager = socketmgr; +#endif + if (manager == NULL) return (ISC_R_NOTFOUND); #if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) - (void)process_fds(socketmgr, socketmgr->events, swait->nevents); + (void)process_fds(manager, manager->events, swait->nevents); return (ISC_R_SUCCESS); #elif defined(USE_SELECT) - process_fds(socketmgr, swait->maxfd, swait->readset, swait->writeset); + process_fds(manager, swait->maxfd, swait->readset, swait->writeset); return (ISC_R_SUCCESS); #endif } -#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* USE_WATCHER_THREAD */ +#ifdef BIND9 void -isc_socket_setname(isc_socket_t *socket, const char *name, void *tag) { +isc__socket_setname(isc_socket_t *socket0, const char *name, void *tag) { + isc__socket_t *socket = (isc__socket_t *)socket0; /* * Name 'socket'. @@ -5482,17 +5770,29 @@ isc_socket_setname(isc_socket_t *socket, const char *name, void *tag) { UNLOCK(&socket->lock); } -const char * -isc_socket_getname(isc_socket_t *socket) { +ISC_SOCKETFUNC_SCOPE const char * +isc__socket_getname(isc_socket_t *socket0) { + isc__socket_t *socket = (isc__socket_t *)socket0; + return (socket->name); } void * -isc_socket_gettag(isc_socket_t *socket) { +isc__socket_gettag(isc_socket_t *socket0) { + isc__socket_t *socket = (isc__socket_t *)socket0; + return (socket->tag); } +#endif /* BIND9 */ -#ifdef HAVE_LIBXML2 +#ifdef USE_SOCKETIMPREGISTER +isc_result_t +isc__socket_register() { + return (isc_socket_register(isc__socketmgr_create)); +} +#endif + +#if defined(HAVE_LIBXML2) && defined(BIND9) static const char * _socktype(isc_sockettype_t type) @@ -5509,21 +5809,21 @@ _socktype(isc_sockettype_t type) return ("not-initialized"); } -void -isc_socketmgr_renderxml(isc_socketmgr_t *mgr, xmlTextWriterPtr writer) -{ - isc_socket_t *sock; +ISC_SOCKETFUNC_SCOPE void +isc_socketmgr_renderxml(isc_socketmgr_t *mgr0, xmlTextWriterPtr writer) { + isc__socketmgr_t *mgr = (isc__socketmgr_t *)mgr0; + isc__socket_t *sock; char peerbuf[ISC_SOCKADDR_FORMATSIZE]; isc_sockaddr_t addr; ISC_SOCKADDR_LEN_T len; LOCK(&mgr->lock); -#ifndef ISC_PLATFORM_USETHREADS +#ifdef USE_SHARED_MANAGER xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"); xmlTextWriterWriteFormatString(writer, "%d", mgr->refs); xmlTextWriterEndElement(writer); -#endif +#endif /* USE_SHARED_MANAGER */ xmlTextWriterStartElement(writer, ISC_XMLCHAR "sockets"); sock = ISC_LIST_HEAD(mgr->socklist); diff --git a/lib/isc/unix/socket_p.h b/lib/isc/unix/socket_p.h index b9a2347..b6c4b6a 100644 --- a/lib/isc/unix/socket_p.h +++ b/lib/isc/unix/socket_p.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: socket_p.h,v 1.13 2008-06-23 23:47:11 tbox Exp $ */ +/* $Id: socket_p.h,v 1.15 2009-09-02 23:48:03 tbox Exp $ */ #ifndef ISC_SOCKET_P_H #define ISC_SOCKET_P_H @@ -27,6 +27,7 @@ #endif typedef struct isc_socketwait isc_socketwait_t; -int isc__socketmgr_waitevents(struct timeval *, isc_socketwait_t **); -isc_result_t isc__socketmgr_dispatch(isc_socketwait_t *); +int isc__socketmgr_waitevents(isc_socketmgr_t *, struct timeval *, + isc_socketwait_t **); +isc_result_t isc__socketmgr_dispatch(isc_socketmgr_t *, isc_socketwait_t *); #endif /* ISC_SOCKET_P_H */ diff --git a/lib/isc/unix/strerror.c b/lib/isc/unix/strerror.c index 08ea52d..4a61a97 100644 --- a/lib/isc/unix/strerror.c +++ b/lib/isc/unix/strerror.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: strerror.c,v 1.8.332.2 2009-02-16 23:47:15 tbox Exp $ */ +/* $Id: strerror.c,v 1.10 2009-02-16 23:48:04 tbox Exp $ */ /*! \file */ diff --git a/lib/isccc/Makefile.in b/lib/isccc/Makefile.in index fb08fcd..1417172 100644 --- a/lib/isccc/Makefile.in +++ b/lib/isccc/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004, 2007, 2009, 2011 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 2001, 2003 Internet Software Consortium. # # Permission to use, copy, modify, and/or distribute this software for any @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.9 2007-06-19 23:47:21 tbox Exp $ +# $Id: Makefile.in,v 1.12.244.1.2.1 2011-06-02 23:47:37 tbox Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -71,7 +71,7 @@ libisccc.la: ${OBJS} ${LIBTOOL_MODE_LINK} \ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisccc.la -rpath ${libdir} \ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ - ${OBJS} ${LIBS} ${ISCLIBS} + ${OBJS} ${ISCLIBS} ${LIBS} timestamp: libisccc.@A@ touch timestamp diff --git a/lib/isccc/api b/lib/isccc/api index 2240cdd..94575eb 100644 --- a/lib/isccc/api +++ b/lib/isccc/api @@ -1,3 +1,3 @@ -LIBINTERFACE = 50 -LIBREVISION = 1 +LIBINTERFACE = 80 +LIBREVISION = 0 LIBAGE = 0 diff --git a/lib/isccfg/Makefile.in b/lib/isccfg/Makefile.in index 4c55a16..37b0a26 100644 --- a/lib/isccfg/Makefile.in +++ b/lib/isccfg/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2004, 2005, 2007, 2009, 2011 Internet Systems Consortium, Inc. ("ISC") # Copyright (C) 2001-2003 Internet Software Consortium. # # Permission to use, copy, modify, and/or distribute this software for any @@ -13,7 +13,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.18 2007-06-19 23:47:22 tbox Exp $ +# $Id: Makefile.in,v 1.21.244.1.2.1 2011-06-02 23:47:37 tbox Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -27,7 +27,7 @@ top_srcdir = @top_srcdir@ CINCLUDES = -I. ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} -CDEFINES = @USE_DLZ@ +CDEFINES = @USE_DLZ@ CWARNINGS = ISCLIBS = ../../lib/isc/libisc.@A@ @@ -68,7 +68,7 @@ libisccfg.la: ${OBJS} ${LIBTOOL_MODE_LINK} \ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisccfg.la -rpath ${libdir} \ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ - ${OBJS} ${LIBS} ${DNSLIBS} ${ISCCCLIBS} ${ISCLIBS} + ${OBJS} ${DNSLIBS} ${ISCCCLIBS} ${ISCLIBS} ${LIBS} timestamp: libisccfg.@A@ touch timestamp diff --git a/lib/isccfg/aclconf.c b/lib/isccfg/aclconf.c index 6bf0ad8..44d436a4 100644 --- a/lib/isccfg/aclconf.c +++ b/lib/isccfg/aclconf.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: aclconf.c,v 1.22.34.4 2009-10-01 23:47:17 tbox Exp $ */ +/* $Id: aclconf.c,v 1.29 2010-08-13 23:47:03 tbox Exp $ */ #include @@ -39,7 +39,7 @@ cfg_aclconfctx_init(cfg_aclconfctx_t *ctx) { } void -cfg_aclconfctx_destroy(cfg_aclconfctx_t *ctx) { +cfg_aclconfctx_clear(cfg_aclconfctx_t *ctx) { dns_acl_t *dacl, *next; for (dacl = ISC_LIST_HEAD(ctx->named_acl_cache); @@ -51,6 +51,23 @@ cfg_aclconfctx_destroy(cfg_aclconfctx_t *ctx) { } } +void +cfg_aclconfctx_clone(cfg_aclconfctx_t *src, cfg_aclconfctx_t *dest) { + dns_acl_t *dacl, *next; + REQUIRE(src != NULL && dest != NULL); + + cfg_aclconfctx_init(dest); + for (dacl = ISC_LIST_HEAD(src->named_acl_cache); + dacl != NULL; + dacl = next) + { + dns_acl_t *copy; + next = ISC_LIST_NEXT(dacl, nextincache); + dns_acl_attach(dacl, ©); + ISC_LIST_APPEND(dest->named_acl_cache, copy, nextincache); + } +} + /* * Find the definition of the named acl whose name is "name". */ @@ -150,7 +167,7 @@ convert_keyname(const cfg_obj_t *keyobj, isc_log_t *lctx, isc_mem_t *mctx, isc_buffer_add(&buf, keylen); dns_fixedname_init(&fixname); result = dns_name_fromtext(dns_fixedname_name(&fixname), &buf, - dns_rootname, ISC_FALSE, NULL); + dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(keyobj, lctx, ISC_LOG_WARNING, "key name '%s' is not a valid domain name", diff --git a/lib/isccfg/api b/lib/isccfg/api index fbbf923..7821c32 100644 --- a/lib/isccfg/api +++ b/lib/isccfg/api @@ -1,3 +1,3 @@ -LIBINTERFACE = 50 -LIBREVISION = 3 -LIBAGE = 0 +LIBINTERFACE = 81 +LIBREVISION = 1 +LIBAGE = 1 diff --git a/lib/isccfg/dnsconf.c b/lib/isccfg/dnsconf.c new file mode 100644 index 0000000..7091d63 --- /dev/null +++ b/lib/isccfg/dnsconf.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: dnsconf.c,v 1.4 2009-09-02 23:48:03 tbox Exp $ */ + +/*! \file */ + +#include + +#include +#include + +/*% + * A trusted key, as used in the "trusted-keys" statement. + */ +static cfg_tuplefielddef_t trustedkey_fields[] = { + { "name", &cfg_type_astring, 0 }, + { "flags", &cfg_type_uint32, 0 }, + { "protocol", &cfg_type_uint32, 0 }, + { "algorithm", &cfg_type_uint32, 0 }, + { "key", &cfg_type_qstring, 0 }, + { NULL, NULL, 0 } +}; + +static cfg_type_t cfg_type_trustedkey = { + "trustedkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, trustedkey_fields +}; + +static cfg_type_t cfg_type_trustedkeys = { + "trusted-keys", cfg_parse_bracketed_list, cfg_print_bracketed_list, + cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_trustedkey +}; + +/*% + * Clauses that can be found within the top level of the dns.conf + * file only. + */ +static cfg_clausedef_t +dnsconf_clauses[] = { + { "trusted-keys", &cfg_type_trustedkeys, CFG_CLAUSEFLAG_MULTI }, + { NULL, NULL, 0 } +}; + +/*% The top-level dns.conf syntax. */ + +static cfg_clausedef_t * +dnsconf_clausesets[] = { + dnsconf_clauses, + NULL +}; + +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_dnsconf = { + "dnsconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, + &cfg_rep_map, dnsconf_clausesets +}; diff --git a/lib/isccfg/include/isccfg/aclconf.h b/lib/isccfg/include/isccfg/aclconf.h index f2ab70f..49aef03 100644 --- a/lib/isccfg/include/isccfg/aclconf.h +++ b/lib/isccfg/include/isccfg/aclconf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: aclconf.h,v 1.10 2007-10-12 04:17:18 each Exp $ */ +/* $Id: aclconf.h,v 1.12 2010-08-13 23:47:04 tbox Exp $ */ #ifndef ISCCFG_ACLCONF_H #define ISCCFG_ACLCONF_H 1 @@ -44,9 +44,15 @@ cfg_aclconfctx_init(cfg_aclconfctx_t *ctx); */ void -cfg_aclconfctx_destroy(cfg_aclconfctx_t *ctx); +cfg_aclconfctx_clone(cfg_aclconfctx_t *src, cfg_aclconfctx_t *dest); /* - * Destroy an ACL configuration context. + * Copy the contents of one ACL configuration context into another. + */ + +void +cfg_aclconfctx_clear(cfg_aclconfctx_t *ctx); +/* + * Clear the contents of an ACL configuration context. */ isc_result_t diff --git a/lib/isccfg/include/isccfg/cfg.h b/lib/isccfg/include/isccfg/cfg.h index 06efa35..82900d6 100644 --- a/lib/isccfg/include/isccfg/cfg.h +++ b/lib/isccfg/include/isccfg/cfg.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cfg.h,v 1.44 2007-10-12 04:17:18 each Exp $ */ +/* $Id: cfg.h,v 1.46 2010-08-13 23:47:04 tbox Exp $ */ #ifndef ISCCFG_CFG_H #define ISCCFG_CFG_H 1 @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -70,7 +71,7 @@ typedef struct cfg_obj cfg_obj_t; typedef struct cfg_listelt cfg_listelt_t; /*% - * A callback function to be called when parsing an option + * A callback function to be called when parsing an option * that needs to be interpreted at parsing time, like * "directory". */ @@ -83,6 +84,12 @@ typedef isc_result_t ISC_LANG_BEGINDECLS +void +cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest); +/*%< + * Reference a parser object. + */ + isc_result_t cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret); /*%< @@ -123,7 +130,7 @@ cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer, * (isc_parse_buffer()). * * Returns an error if the file does not parse correctly. - * + * * Requires: *\li "filename" is valid. *\li "mem" is valid. @@ -140,13 +147,14 @@ cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer, void cfg_parser_destroy(cfg_parser_t **pctxp); /*%< - * Destroy a configuration parser. + * Remove a reference to a configuration parser; destroy it if there are no + * more references. */ isc_boolean_t cfg_obj_isvoid(const cfg_obj_t *obj); /*%< - * Return true iff 'obj' is of void type (e.g., an optional + * Return true iff 'obj' is of void type (e.g., an optional * value not specified). */ @@ -355,7 +363,7 @@ cfg_list_length(const cfg_obj_t *obj, isc_boolean_t recurse); * all contained lists. */ -const cfg_obj_t * +cfg_obj_t * cfg_listelt_value(const cfg_listelt_t *elt); /*%< * Returns the configuration object associated with cfg_listelt_t. @@ -389,17 +397,25 @@ cfg_print_grammar(const cfg_type_t *type, isc_boolean_t cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type); /*%< - * Return true iff 'obj' is of type 'type'. + * Return true iff 'obj' is of type 'type'. */ -void cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **obj); +void +cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest); +/*%< + * Reference a configuration object. + */ + +void +cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **obj); /*%< - * Destroy a configuration object. + * Delete a reference to a configuration object; destroy the object if + * there are no more references. */ void cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level, - const char *fmt, ...) + const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5); /*%< * Log a message concerning configuration object 'obj' to the logging diff --git a/lib/isccfg/include/isccfg/dnsconf.h b/lib/isccfg/include/isccfg/dnsconf.h new file mode 100644 index 0000000..bb71338 --- /dev/null +++ b/lib/isccfg/include/isccfg/dnsconf.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC 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. + */ + +/* $Id: dnsconf.h,v 1.3 2009-09-02 23:48:03 tbox Exp $ */ + +#ifndef ISCCFG_NAMEDCONF_H +#define ISCCFG_NAMEDCONF_H 1 + +/*! \file + * \brief + * This module defines the named.conf, rndc.conf, and rndc.key grammars. + */ + +#include + +/* + * Configuration object types. + */ +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_dnsconf; +/*%< A complete dns.conf file. */ + +#endif /* ISCCFG_CFG_H */ diff --git a/lib/isccfg/include/isccfg/grammar.h b/lib/isccfg/include/isccfg/grammar.h index b8b845b..afc95bc 100644 --- a/lib/isccfg/include/isccfg/grammar.h +++ b/lib/isccfg/include/isccfg/grammar.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: grammar.h,v 1.17 2008-09-25 04:02:39 tbox Exp $ */ +/* $Id: grammar.h,v 1.24 2011-01-04 23:47:14 tbox Exp $ */ #ifndef ISCCFG_GRAMMAR_H #define ISCCFG_GRAMMAR_H 1 @@ -53,6 +53,8 @@ #define CFG_CLAUSEFLAG_CALLBACK 0x00000020 /*% A option that is only used in testing. */ #define CFG_CLAUSEFLAG_TESTONLY 0x00000040 +/*% A configuration option that was not configured at compile time. */ +#define CFG_CLAUSEFLAG_NOTCONFIGURED 0x00000080 typedef struct cfg_clausedef cfg_clausedef_t; typedef struct cfg_tuplefielddef cfg_tuplefielddef_t; @@ -157,6 +159,7 @@ struct cfg_obj { isc_sockaddr_t sockaddr; cfg_netprefix_t netprefix; } value; + isc_refcount_t references; /*%< reference counter */ const char * file; unsigned int line; }; @@ -210,10 +213,21 @@ struct cfg_parser { */ unsigned int line; + /*% + * Parser context flags, used for maintaining state + * from one token to the next. + */ + unsigned int flags; + + /*%< Reference counter */ + isc_refcount_t references; + cfg_parsecallback_t callback; void *callbackarg; }; +/* Parser context flags */ +#define CFG_PCTX_SKIP 0x1 /*@{*/ /*% @@ -314,10 +328,16 @@ cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port); isc_result_t cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); +isc_result_t +cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); + void cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj); void +cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj); + +void cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type); isc_result_t diff --git a/lib/isccfg/include/isccfg/log.h b/lib/isccfg/include/isccfg/log.h index f45e4c2..2c9dc12 100644 --- a/lib/isccfg/include/isccfg/log.h +++ b/lib/isccfg/include/isccfg/log.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: log.h,v 1.12.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: log.h,v 1.14 2009-01-18 23:48:14 tbox Exp $ */ #ifndef ISCCFG_LOG_H #define ISCCFG_LOG_H 1 diff --git a/lib/isccfg/include/isccfg/namedconf.h b/lib/isccfg/include/isccfg/namedconf.h index 34aa3e8..9242cf3 100644 --- a/lib/isccfg/include/isccfg/namedconf.h +++ b/lib/isccfg/include/isccfg/namedconf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: namedconf.h,v 1.9.332.2 2009-06-25 23:47:28 tbox Exp $ */ +/* $Id: namedconf.h,v 1.18 2010-08-11 18:14:20 each Exp $ */ #ifndef ISCCFG_NAMEDCONF_H #define ISCCFG_NAMEDCONF_H 1 @@ -33,12 +33,24 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_namedconf; /*%< A complete named.conf file. */ +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_bindkeys; +/*%< A bind.keys file. */ + +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_newzones; +/*%< A new-zones file (for zones added by 'rndc addzone'). */ + +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_addzoneconf; +/*%< A single zone passed via the addzone rndc command. */ + LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_rndcconf; /*%< A complete rndc.conf file. */ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_rndckey; /*%< A complete rndc.key file. */ +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sessionkey; +/*%< A complete session.key file. */ + LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_keyref; /*%< A key reference, used as an ACL element */ diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index f291507..f80d34b 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2002, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: namedconf.c,v 1.92.44.2 2010-05-13 23:47:49 tbox Exp $ */ +/* $Id: namedconf.c,v 1.131.8.1 2011-02-03 05:50:08 marka Exp $ */ /*! \file */ @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -35,9 +36,9 @@ #define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base) /*% Check a return value. */ -#define CHECK(op) \ - do { result = (op); \ - if (result != ISC_R_SUCCESS) goto cleanup; \ +#define CHECK(op) \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) goto cleanup; \ } while (0) /*% Clean up a configuration object if non-NULL. */ @@ -57,7 +58,17 @@ static isc_result_t parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); static isc_result_t -parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); +parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret); + +static isc_result_t +parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret); +static void +print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj); + +static void +doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type); static void print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj); @@ -111,6 +122,7 @@ static cfg_type_t cfg_type_zone; static cfg_type_t cfg_type_zoneopts; static cfg_type_t cfg_type_dynamically_loadable_zones; static cfg_type_t cfg_type_dynamically_loadable_zones_opts; +static cfg_type_t cfg_type_v4_aaaa; /* * Clauses that can be found in a 'dynamically loadable zones' statement @@ -241,30 +253,76 @@ static cfg_tuplefielddef_t pubkey_fields[] = { { NULL, NULL, 0 } }; static cfg_type_t cfg_type_pubkey = { - "pubkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, pubkey_fields }; + "pubkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, pubkey_fields }; /*% * A list of RR types, used in grant statements. * Note that the old parser allows quotes around the RR type names. */ static cfg_type_t cfg_type_rrtypelist = { - "rrtypelist", cfg_parse_spacelist, cfg_print_spacelist, cfg_doc_terminal, - &cfg_rep_list, &cfg_type_astring + "rrtypelist", cfg_parse_spacelist, cfg_print_spacelist, + cfg_doc_terminal, &cfg_rep_list, &cfg_type_astring }; static const char *mode_enums[] = { "grant", "deny", NULL }; static cfg_type_t cfg_type_mode = { - "mode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string, - &mode_enums + "mode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, + &cfg_rep_string, &mode_enums }; +static isc_result_t +parse_matchtype(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) { + isc_result_t result; + + CHECK(cfg_peektoken(pctx, 0)); + if (pctx->token.type == isc_tokentype_string && + strcasecmp(TOKEN_STRING(pctx), "zonesub") == 0) { + pctx->flags |= CFG_PCTX_SKIP; + } + return (cfg_parse_enum(pctx, type, ret)); + + cleanup: + return (result); +} + +static isc_result_t +parse_matchname(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { + isc_result_t result; + cfg_obj_t *obj = NULL; + + if ((pctx->flags & CFG_PCTX_SKIP) != 0) { + pctx->flags &= ~CFG_PCTX_SKIP; + CHECK(cfg_parse_void(pctx, NULL, &obj)); + } else + result = cfg_parse_astring(pctx, type, &obj); + + *ret = obj; + cleanup: + return (result); +} + +static void +doc_matchname(cfg_printer_t *pctx, const cfg_type_t *type) { + cfg_print_chars(pctx, "[ ", 2); + cfg_doc_obj(pctx, type->of); + cfg_print_chars(pctx, " ]", 2); +} + static const char *matchtype_enums[] = { "name", "subdomain", "wildcard", "self", "selfsub", "selfwild", "krb5-self", "ms-self", "krb5-subdomain", "ms-subdomain", - "tcp-self", "6to4-self", NULL }; + "tcp-self", "6to4-self", "zonesub", "external", NULL }; + static cfg_type_t cfg_type_matchtype = { - "matchtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string, - &matchtype_enums + "matchtype", parse_matchtype, cfg_print_ustring, + cfg_doc_enum, &cfg_rep_string, &matchtype_enums +}; + +static cfg_type_t cfg_type_matchname = { + "optional_matchname", parse_matchname, cfg_print_ustring, + &doc_matchname, &cfg_rep_tuple, &cfg_type_ustring }; /*% @@ -274,18 +332,70 @@ static cfg_tuplefielddef_t grant_fields[] = { { "mode", &cfg_type_mode, 0 }, { "identity", &cfg_type_astring, 0 }, /* domain name */ { "matchtype", &cfg_type_matchtype, 0 }, - { "name", &cfg_type_astring, 0 }, /* domain name */ + { "name", &cfg_type_matchname, 0 }, /* domain name */ { "types", &cfg_type_rrtypelist, 0 }, { NULL, NULL, 0 } }; static cfg_type_t cfg_type_grant = { - "grant", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, grant_fields }; + "grant", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, grant_fields +}; static cfg_type_t cfg_type_updatepolicy = { - "update_policy", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, - &cfg_rep_list, &cfg_type_grant + "update_policy", parse_updatepolicy, print_updatepolicy, + doc_updatepolicy, &cfg_rep_list, &cfg_type_grant }; +static isc_result_t +parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) { + isc_result_t result; + CHECK(cfg_gettoken(pctx, 0)); + if (pctx->token.type == isc_tokentype_special && + pctx->token.value.as_char == '{') { + cfg_ungettoken(pctx); + return (cfg_parse_bracketed_list(pctx, type, ret)); + } + + if (pctx->token.type == isc_tokentype_string && + strcasecmp(TOKEN_STRING(pctx), "local") == 0) { + cfg_obj_t *obj = NULL; + CHECK(cfg_create_obj(pctx, &cfg_type_ustring, &obj)); + obj->value.string.length = strlen("local"); + obj->value.string.base = isc_mem_get(pctx->mctx, + obj->value.string.length + 1); + if (obj->value.string.base == NULL) { + isc_mem_put(pctx->mctx, obj, sizeof(*obj)); + return (ISC_R_NOMEMORY); + } + memcpy(obj->value.string.base, "local", 5); + obj->value.string.base[5] = '\0'; + *ret = obj; + return (ISC_R_SUCCESS); + } + + cfg_ungettoken(pctx); + return (ISC_R_UNEXPECTEDTOKEN); + + cleanup: + return (result); +} + +static void +print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj) { + if (cfg_obj_isstring(obj)) + cfg_print_ustring(pctx, obj); + else + cfg_print_bracketed_list(pctx, obj); +} + +static void +doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type) { + cfg_print_cstr(pctx, "( local | { "); + cfg_doc_obj(pctx, type->of); + cfg_print_cstr(pctx, "; ... }"); +} + /*% * A view statement. */ @@ -296,7 +406,9 @@ static cfg_tuplefielddef_t view_fields[] = { { NULL, NULL, 0 } }; static cfg_type_t cfg_type_view = { - "view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, view_fields }; + "view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, view_fields +}; /*% * A zone statement. @@ -308,7 +420,9 @@ static cfg_tuplefielddef_t zone_fields[] = { { NULL, NULL, 0 } }; static cfg_type_t cfg_type_zone = { - "zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, zone_fields }; + "zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, zone_fields +}; /*% * A "category" clause in the "logging" statement. @@ -319,13 +433,15 @@ static cfg_tuplefielddef_t category_fields[] = { { NULL, NULL, 0 } }; static cfg_type_t cfg_type_category = { - "category", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, category_fields }; + "category", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, category_fields +}; /*% - * A trusted key, as used in the "trusted-keys" statement. + * A dnssec key, as used in the "trusted-keys" statement. */ -static cfg_tuplefielddef_t trustedkey_fields[] = { +static cfg_tuplefielddef_t dnsseckey_fields[] = { { "name", &cfg_type_astring, 0 }, { "flags", &cfg_type_uint32, 0 }, { "protocol", &cfg_type_uint32, 0 }, @@ -333,9 +449,27 @@ static cfg_tuplefielddef_t trustedkey_fields[] = { { "key", &cfg_type_qstring, 0 }, { NULL, NULL, 0 } }; -static cfg_type_t cfg_type_trustedkey = { - "trustedkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, - trustedkey_fields +static cfg_type_t cfg_type_dnsseckey = { + "dnsseckey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, dnsseckey_fields +}; + +/*% + * A managed key initialization specifier, as used in the + * "managed-keys" statement. + */ +static cfg_tuplefielddef_t managedkey_fields[] = { + { "name", &cfg_type_astring, 0 }, + { "init", &cfg_type_ustring, 0 }, /* must be literal "initial-key" */ + { "flags", &cfg_type_uint32, 0 }, + { "protocol", &cfg_type_uint32, 0 }, + { "algorithm", &cfg_type_uint32, 0 }, + { "key", &cfg_type_qstring, 0 }, + { NULL, NULL, 0 } +}; +static cfg_type_t cfg_type_managedkey = { + "managedkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, managedkey_fields }; static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring }; @@ -397,6 +531,7 @@ static cfg_tuplefielddef_t checknames_fields[] = { { "mode", &cfg_type_checkmode, 0 }, { NULL, NULL, 0 } }; + static cfg_type_t cfg_type_checknames = { "checknames", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, checknames_fields @@ -407,6 +542,13 @@ static cfg_type_t cfg_type_bracketed_sockaddrlist = { &cfg_rep_list, &cfg_type_sockaddr }; +static const char *autodnssec_enums[] = { "allow", "maintain", "create", + "off", NULL }; +static cfg_type_t cfg_type_autodnssec = { + "autodnssec", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, + &cfg_rep_string, &autodnssec_enums +}; + static cfg_type_t cfg_type_rrsetorder = { "rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_rrsetorderingelement @@ -421,13 +563,27 @@ static cfg_type_t cfg_type_optional_port = { /*% A list of keys, as in the "key" clause of the controls statement. */ static cfg_type_t cfg_type_keylist = { - "keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, - &cfg_type_astring + "keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list, + cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring +}; + +/*% A list of dnssec keys, as in "trusted-keys" */ +static cfg_type_t cfg_type_dnsseckeys = { + "dnsseckeys", cfg_parse_bracketed_list, cfg_print_bracketed_list, + cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_dnsseckey }; -static cfg_type_t cfg_type_trustedkeys = { - "trusted-keys", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, - &cfg_type_trustedkey +/*% + * A list of managed key entries, as in "trusted-keys". Currently + * (9.7.0) this has a format similar to dnssec keys, except the keyname + * is followed by the keyword "initial-key". In future releases, this + * keyword may take other values indicating different methods for the + * key to be initialized. + */ + +static cfg_type_t cfg_type_managedkeys = { + "managedkeys", cfg_parse_bracketed_list, cfg_print_bracketed_list, + cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_managedkey }; static const char *forwardtype_enums[] = { "first", "only", NULL }; @@ -437,7 +593,8 @@ static cfg_type_t cfg_type_forwardtype = { }; static const char *zonetype_enums[] = { - "master", "slave", "stub", "hint", "forward", "delegation-only", NULL }; + "master", "slave", "stub", "static-stub", "hint", "forward", + "delegation-only", NULL }; static cfg_type_t cfg_type_zonetype = { "zonetype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string, &zonetype_enums @@ -479,6 +636,7 @@ parse_qstringornone(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; + CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); if (pctx->token.type == isc_tokentype_string && strcasecmp(TOKEN_STRING(pctx), "none") == 0) @@ -496,13 +654,65 @@ doc_qstringornone(cfg_printer_t *pctx, const cfg_type_t *type) { } static cfg_type_t cfg_type_qstringornone = { - "qstringornone", parse_qstringornone, NULL, doc_qstringornone, NULL, NULL }; + "qstringornone", parse_qstringornone, NULL, doc_qstringornone, + NULL, NULL +}; /*% - * keyword hostname + * A boolean ("yes" or "no"), or the special keyword "auto". + * Used in the dnssec-validation option. */ +static void +print_auto(cfg_printer_t *pctx, const cfg_obj_t *obj) { + UNUSED(obj); + cfg_print_cstr(pctx, "auto"); +} + +static cfg_type_t cfg_type_auto = { + "auto", NULL, print_auto, NULL, &cfg_rep_void, NULL +}; + +static isc_result_t +parse_boolorauto(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) +{ + isc_result_t result; + + CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); + if (pctx->token.type == isc_tokentype_string && + strcasecmp(TOKEN_STRING(pctx), "auto") == 0) + return (cfg_create_obj(pctx, &cfg_type_auto, ret)); + cfg_ungettoken(pctx); + return (cfg_parse_boolean(pctx, type, ret)); + cleanup: + return (result); +} static void +print_boolorauto(cfg_printer_t *pctx, const cfg_obj_t *obj) { + if (obj->type->rep == &cfg_rep_void) + cfg_print_chars(pctx, "auto", 4); + else if (obj->value.boolean) + cfg_print_chars(pctx, "yes", 3); + else + cfg_print_chars(pctx, "no", 2); +} + +static void +doc_boolorauto(cfg_printer_t *pctx, const cfg_type_t *type) { + UNUSED(type); + cfg_print_cstr(pctx, "( yes | no | auto )"); +} + +static cfg_type_t cfg_type_boolorauto = { + "boolorauto", parse_boolorauto, print_boolorauto, + doc_boolorauto, NULL, NULL +}; + +/*% + * keyword hostname + */ +static void print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) { UNUSED(obj); cfg_print_cstr(pctx, "hostname"); @@ -652,7 +862,18 @@ namedconf_or_view_clauses[] = { /* only 1 DLZ per view allowed */ { "dlz", &cfg_type_dynamically_loadable_zones, 0 }, { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI }, - { "trusted-keys", &cfg_type_trustedkeys, CFG_CLAUSEFLAG_MULTI }, + { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI }, + { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI }, + { NULL, NULL, 0 } +}; + +/*% + * Clauses that can occur in the bind.keys file. + */ +static cfg_clausedef_t +bindkeys_clauses[] = { + { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI }, + { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI }, { NULL, NULL, 0 } }; @@ -661,18 +882,21 @@ namedconf_or_view_clauses[] = { */ static cfg_clausedef_t options_clauses[] = { - { "use-v4-udp-ports", &cfg_type_bracketed_portlist, 0 }, - { "use-v6-udp-ports", &cfg_type_bracketed_portlist, 0 }, { "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 }, { "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 }, + { "bindkeys-file", &cfg_type_qstring, 0 }, { "blackhole", &cfg_type_bracketed_aml, 0 }, { "coresize", &cfg_type_size, 0 }, { "datasize", &cfg_type_size, 0 }, + { "session-keyfile", &cfg_type_qstringornone, 0 }, + { "session-keyname", &cfg_type_astring, 0 }, + { "session-keyalg", &cfg_type_astring, 0 }, { "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, { "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK }, { "dump-file", &cfg_type_qstring, 0 }, { "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, { "files", &cfg_type_size, 0 }, + { "flush-zones-on-shutdown", &cfg_type_boolean, 0 }, { "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, { "heartbeat-interval", &cfg_type_uint32, 0 }, { "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP }, @@ -681,6 +905,7 @@ options_clauses[] = { { "interface-interval", &cfg_type_uint32, 0 }, { "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI }, { "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI }, + { "managed-keys-directory", &cfg_type_qstring, 0 }, { "match-mapped-addresses", &cfg_type_boolean, 0 }, { "memstatistics-file", &cfg_type_qstring, 0 }, { "memstatistics", &cfg_type_boolean, 0 }, @@ -693,6 +918,7 @@ options_clauses[] = { { "random-device", &cfg_type_qstring, 0 }, { "recursive-clients", &cfg_type_uint32, 0 }, { "reserved-sockets", &cfg_type_uint32, 0 }, + { "secroots-file", &cfg_type_qstring, 0 }, { "serial-queries", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE }, { "serial-query-rate", &cfg_type_uint32, 0 }, { "server-id", &cfg_type_serverid, 0 }, @@ -703,6 +929,7 @@ options_clauses[] = { { "tcp-listen-queue", &cfg_type_uint32, 0 }, { "tkey-dhkey", &cfg_type_tkey_dhkey, 0 }, { "tkey-gssapi-credential", &cfg_type_qstring, 0 }, + { "tkey-gssapi-keytab", &cfg_type_qstring, 0 }, { "tkey-domain", &cfg_type_qstring, 0 }, { "transfers-per-ns", &cfg_type_uint32, 0 }, { "transfers-in", &cfg_type_uint32, 0 }, @@ -710,12 +937,12 @@ options_clauses[] = { { "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, { "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, { "use-ixfr", &cfg_type_boolean, 0 }, + { "use-v4-udp-ports", &cfg_type_bracketed_portlist, 0 }, + { "use-v6-udp-ports", &cfg_type_bracketed_portlist, 0 }, { "version", &cfg_type_qstringornone, 0 }, - { "flush-zones-on-shutdown", &cfg_type_boolean, 0 }, { NULL, NULL, 0 } }; - static cfg_type_t cfg_type_namelist = { "namelist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_qstring }; @@ -726,6 +953,34 @@ static cfg_type_t cfg_type_optional_exclude = { "optional_exclude", parse_optional_keyvalue, print_keyvalue, doc_optional_keyvalue, &cfg_rep_list, &exclude_kw }; +static keyword_type_t exceptionnames_kw = { "except-from", &cfg_type_namelist }; + +static cfg_type_t cfg_type_optional_exceptionnames = { + "optional_allow", parse_optional_keyvalue, print_keyvalue, + doc_optional_keyvalue, &cfg_rep_list, &exceptionnames_kw }; + +static cfg_tuplefielddef_t denyaddresses_fields[] = { + { "acl", &cfg_type_bracketed_aml, 0 }, + { "except-from", &cfg_type_optional_exceptionnames, 0 }, + { NULL, NULL, 0 } +}; + +static cfg_type_t cfg_type_denyaddresses = { + "denyaddresses", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, denyaddresses_fields +}; + +static cfg_tuplefielddef_t denyaliases_fields[] = { + { "name", &cfg_type_namelist, 0 }, + { "except-from", &cfg_type_optional_exceptionnames, 0 }, + { NULL, NULL, 0 } +}; + +static cfg_type_t cfg_type_denyaliases = { + "denyaliases", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, denyaliases_fields +}; + static cfg_type_t cfg_type_algorithmlist = { "algorithmlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring }; @@ -758,20 +1013,134 @@ static cfg_type_t cfg_type_masterformat = { &cfg_rep_string, &masterformat_enums }; + + +/* + * response-policy { + * zone [ policy (given|no-op|nxdomain|nodata|cname ) ]; + * }; + * + * this is a chimera of doc_optional_keyvalue() and cfg_doc_enum() + */ +static void +doc_rpz_policies(cfg_printer_t *pctx, const cfg_type_t *type) { + const keyword_type_t *kw; + const char * const *p; + + kw = type->of; + cfg_print_chars(pctx, "[ ", 2); + cfg_print_cstr(pctx, kw->name); + cfg_print_chars(pctx, " ", 1); + + cfg_print_chars(pctx, "( ", 2); + for (p = kw->type->of; *p != NULL; p++) { + cfg_print_cstr(pctx, *p); + if (p[1] != NULL) + cfg_print_chars(pctx, " | ", 3); + } +} + +/* + * print_qstring() from parser.c + */ +static void +print_rpz_cname(cfg_printer_t *pctx, const cfg_obj_t *obj) +{ + cfg_print_chars(pctx, "\"", 1); + cfg_print_ustring(pctx, obj); + cfg_print_chars(pctx, "\"", 1); +} + +static void +doc_rpz_cname(cfg_printer_t *pctx, const cfg_type_t *type) { + cfg_doc_terminal(pctx, type); + cfg_print_chars(pctx, " ) ]", 4); +} + +static isc_result_t +parse_rpz(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { + isc_result_t result; + cfg_obj_t *obj = NULL; + const cfg_tuplefielddef_t *fields = type->of; + + CHECK(cfg_create_tuple(pctx, type, &obj)); + CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0])); + CHECK(cfg_parse_obj(pctx, fields[1].type, &obj->value.tuple[1])); + /* + * parse cname domain only after "policy cname" + */ + if (cfg_obj_isvoid(obj->value.tuple[1]) || + strcasecmp("cname", cfg_obj_asstring(obj->value.tuple[1]))) { + CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2])); + } else { + CHECK(cfg_parse_obj(pctx, fields[2].type, &obj->value.tuple[2])); + } + + *ret = obj; + return (ISC_R_SUCCESS); + +cleanup: + CLEANUP_OBJ(obj); + return (result); +} + +static const char *rpz_policies[] = { + "given", "no-op", "nxdomain", "nodata", "cname", NULL +}; +static cfg_type_t cfg_type_rpz_policylist = { + "policies", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, + &cfg_rep_string, &rpz_policies +}; +static keyword_type_t rpz_policies_kw = { + "policy", &cfg_type_rpz_policylist +}; +static cfg_type_t cfg_type_rpz_policy = { + "optional_policy", parse_optional_keyvalue, print_keyvalue, + doc_rpz_policies, &cfg_rep_string, &rpz_policies_kw +}; +static cfg_type_t cfg_type_cname = { + "domain", cfg_parse_astring, print_rpz_cname, doc_rpz_cname, + &cfg_rep_string, NULL +}; +static cfg_tuplefielddef_t rpzone_fields[] = { + { "name", &cfg_type_astring, 0 }, + { "policy", &cfg_type_rpz_policy, 0 }, + { "cname", &cfg_type_cname, 0 }, + { NULL, NULL, 0 } +}; +static cfg_type_t cfg_type_rpzone = { + "rpzone", parse_rpz, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, rpzone_fields +}; +static cfg_clausedef_t rpz_clauses[] = { + { "zone", &cfg_type_rpzone, CFG_CLAUSEFLAG_MULTI }, + { NULL, NULL, 0 } +}; +static cfg_clausedef_t *rpz_clausesets[] = { + rpz_clauses, + NULL +}; +static cfg_type_t cfg_type_rpz = { + "rpz", cfg_parse_map, cfg_print_map, cfg_doc_map, + &cfg_rep_map, rpz_clausesets +}; + + + /*% * dnssec-lookaside */ static keyword_type_t trustanchor_kw = { "trust-anchor", &cfg_type_astring }; -static cfg_type_t cfg_type_trustanchor = { - "trust-anchor", parse_keyvalue, print_keyvalue, doc_keyvalue, - &cfg_rep_string, &trustanchor_kw +static cfg_type_t cfg_type_optional_trustanchor = { + "optional_trustanchor", parse_optional_keyvalue, print_keyvalue, + doc_keyvalue, &cfg_rep_string, &trustanchor_kw }; static cfg_tuplefielddef_t lookaside_fields[] = { { "domain", &cfg_type_astring, 0 }, - { "trust-anchor", &cfg_type_trustanchor, 0 }, + { "trust-anchor", &cfg_type_optional_trustanchor, 0 }, { NULL, NULL, 0 } }; @@ -780,6 +1149,31 @@ static cfg_type_t cfg_type_lookaside = { &cfg_rep_tuple, lookaside_fields }; +/* + * DNS64. + */ +static cfg_clausedef_t +dns64_clauses[] = { + { "clients", &cfg_type_bracketed_aml, 0 }, + { "mapped", &cfg_type_bracketed_aml, 0 }, + { "exclude", &cfg_type_bracketed_aml, 0 }, + { "suffix", &cfg_type_netaddr6, 0 }, + { "recursive-only", &cfg_type_boolean, 0 }, + { "break-dnssec", &cfg_type_boolean, 0 }, + { NULL, NULL, 0 }, +}; + +static cfg_clausedef_t * +dns64_clausesets[] = { + dns64_clauses, + NULL +}; + +static cfg_type_t cfg_type_dns64 = { + "dns64", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map, + &cfg_rep_map, dns64_clausesets +}; + /*% * Clauses that can be found within the 'view' statement, * with defaults in the 'options' statement. @@ -791,26 +1185,33 @@ view_clauses[] = { { "acache-enable", &cfg_type_boolean, 0 }, { "additional-from-auth", &cfg_type_boolean, 0 }, { "additional-from-cache", &cfg_type_boolean, 0 }, + { "allow-new-zones", &cfg_type_boolean, 0 }, { "allow-query-cache", &cfg_type_bracketed_aml, 0 }, { "allow-query-cache-on", &cfg_type_bracketed_aml, 0 }, { "allow-recursion", &cfg_type_bracketed_aml, 0 }, { "allow-recursion-on", &cfg_type_bracketed_aml, 0 }, { "allow-v6-synthesis", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_OBSOLETE }, + { "attach-cache", &cfg_type_astring, 0 }, { "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT }, { "cache-file", &cfg_type_qstring, 0 }, { "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI }, { "cleaning-interval", &cfg_type_uint32, 0 }, { "clients-per-query", &cfg_type_uint32, 0 }, + { "deny-answer-addresses", &cfg_type_denyaddresses, 0 }, + { "deny-answer-aliases", &cfg_type_denyaliases, 0 }, { "disable-algorithms", &cfg_type_disablealgorithm, CFG_CLAUSEFLAG_MULTI }, { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI }, + { "dns64", &cfg_type_dns64, CFG_CLAUSEFLAG_MULTI }, + { "dns64-server", &cfg_type_astring, 0 }, + { "dns64-contact", &cfg_type_astring, 0 }, { "dnssec-accept-expired", &cfg_type_boolean, 0 }, { "dnssec-enable", &cfg_type_boolean, 0 }, { "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI }, { "dnssec-must-be-secure", &cfg_type_mustbesecure, CFG_CLAUSEFLAG_MULTI }, - { "dnssec-validation", &cfg_type_boolean, 0 }, + { "dnssec-validation", &cfg_type_boolorauto, 0 }, { "dual-stack-servers", &cfg_type_nameportiplist, 0 }, { "edns-udp-size", &cfg_type_uint32, 0 }, { "empty-contact", &cfg_type_astring, 0 }, @@ -841,6 +1242,7 @@ view_clauses[] = { { "recursion", &cfg_type_boolean, 0 }, { "request-ixfr", &cfg_type_boolean, 0 }, { "request-nsid", &cfg_type_boolean, 0 }, + { "resolver-query-timeout", &cfg_type_uint32, 0 }, { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI }, { "root-delegation-only", &cfg_type_optional_exclude, 0 }, { "rrset-order", &cfg_type_rrsetorder, 0 }, @@ -850,6 +1252,16 @@ view_clauses[] = { { "transfer-format", &cfg_type_transferformat, 0 }, { "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, { "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 }, +#ifdef ALLOW_FILTER_AAAA_ON_V4 + { "filter-aaaa", &cfg_type_bracketed_aml, 0 }, + { "filter-aaaa-on-v4", &cfg_type_v4_aaaa, 0 }, +#else + { "filter-aaaa", &cfg_type_bracketed_aml, + CFG_CLAUSEFLAG_NOTCONFIGURED }, + { "filter-aaaa-on-v4", &cfg_type_v4_aaaa, + CFG_CLAUSEFLAG_NOTCONFIGURED }, +#endif + { "response-policy", &cfg_type_rpz, 0 }, { NULL, NULL, 0 } }; @@ -920,6 +1332,7 @@ zone_clauses[] = { { "also-notify", &cfg_type_portiplist, 0 }, { "alt-transfer-source", &cfg_type_sockaddr4wild, 0 }, { "alt-transfer-source-v6", &cfg_type_sockaddr6wild, 0 }, + { "check-dup-records", &cfg_type_checkmode, 0 }, { "check-integrity", &cfg_type_boolean, 0 }, { "check-mx", &cfg_type_checkmode, 0 }, { "check-mx-cname", &cfg_type_checkmode, 0 }, @@ -927,6 +1340,8 @@ zone_clauses[] = { { "check-srv-cname", &cfg_type_checkmode, 0 }, { "check-wildcard", &cfg_type_boolean, 0 }, { "dialup", &cfg_type_dialuptype, 0 }, + { "dnssec-dnskey-kskonly", &cfg_type_boolean, 0 }, + { "dnssec-secure-to-insecure", &cfg_type_boolean, 0 }, { "forward", &cfg_type_forwardtype, 0 }, { "forwarders", &cfg_type_portiplist, 0 }, { "key-directory", &cfg_type_qstring, 0 }, @@ -986,6 +1401,9 @@ zone_only_clauses[] = { */ { "check-names", &cfg_type_checkmode, 0 }, { "ixfr-from-differences", &cfg_type_boolean, 0 }, + { "auto-dnssec", &cfg_type_autodnssec, 0 }, + { "server-addresses", &cfg_type_bracketed_sockaddrlist, 0 }, + { "server-names", &cfg_type_namelist, 0 }, { NULL, NULL, 0 } }; @@ -998,12 +1416,40 @@ namedconf_clausesets[] = { namedconf_or_view_clauses, NULL }; - LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = { "namedconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, &cfg_rep_map, namedconf_clausesets }; +/*% The bind.keys syntax (trusted-keys/managed-keys only). */ +static cfg_clausedef_t * +bindkeys_clausesets[] = { + bindkeys_clauses, + NULL +}; +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bindkeys = { + "bindkeys", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, + &cfg_rep_map, bindkeys_clausesets +}; + +/*% The new-zone-file syntax (for zones added by 'rndc addzone') */ +static cfg_clausedef_t +newzones_clauses[] = { + { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI }, + { NULL, NULL, 0 } +}; + +static cfg_clausedef_t * +newzones_clausesets[] = { + newzones_clauses, + NULL +}; + +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_newzones = { + "newzones", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, + &cfg_rep_map, newzones_clausesets +}; + /*% The "options" statement syntax. */ static cfg_clausedef_t * @@ -1166,6 +1612,38 @@ static cfg_type_t cfg_type_logging = { "logging", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, logging_clausesets }; +/*% + * For parsing an 'addzone' statement + */ + +static cfg_tuplefielddef_t addzone_fields[] = { + { "name", &cfg_type_astring, 0 }, + { "class", &cfg_type_optional_class, 0 }, + { "view", &cfg_type_optional_class, 0 }, + { "options", &cfg_type_zoneopts, 0 }, + { NULL, NULL, 0 } +}; +static cfg_type_t cfg_type_addzone = { + "addzone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, addzone_fields }; + +static cfg_clausedef_t +addzoneconf_clauses[] = { + { "addzone", &cfg_type_addzone, 0 }, + { NULL, NULL, 0 } +}; + +static cfg_clausedef_t * +addzoneconf_clausesets[] = { + addzoneconf_clauses, + NULL +}; + +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_addzoneconf = { + "addzoneconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, + &cfg_rep_map, addzoneconf_clausesets +}; + + static isc_result_t parse_unitstring(char *str, isc_resourcevalue_t *valuep) { char *endp; @@ -1385,6 +1863,17 @@ static cfg_type_t cfg_type_ixfrdifftype = { &cfg_rep_string, ixfrdiff_enums, }; +static const char *v4_aaaa_enums[] = { "break-dnssec", NULL }; +static isc_result_t +parse_v4_aaaa(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) { + return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); +} +static cfg_type_t cfg_type_v4_aaaa = { + "v4_aaaa", parse_v4_aaaa, cfg_print_ustring, + doc_enum_or_other, &cfg_rep_string, v4_aaaa_enums, +}; + static keyword_type_t key_kw = { "key", &cfg_type_astring }; LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = { @@ -2082,6 +2571,15 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndckey = { &cfg_rep_map, rndckey_clausesets }; +/* + * session.key has exactly the same syntax as rndc.key, but it's defined + * separately for clarity (and so we can extend it someday, if needed). + */ +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sessionkey = { + "sessionkey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, + &cfg_rep_map, rndckey_clausesets +}; + static cfg_tuplefielddef_t nameport_fields[] = { { "name", &cfg_type_astring, 0 }, { "port", &cfg_type_optional_port, 0 }, diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c index 2f64a09..87ad391 100644 --- a/lib/isccfg/parser.c +++ b/lib/isccfg/parser.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: parser.c,v 1.129 2008-09-25 04:02:39 tbox Exp $ */ +/* $Id: parser.c,v 1.139 2011-01-04 23:47:14 tbox Exp $ */ /*! \file */ @@ -29,12 +29,12 @@ #include #include #include +#include #include #include #include -#include -#include #include +#include #include #include @@ -387,6 +387,12 @@ cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) { if (pctx == NULL) return (ISC_R_NOMEMORY); + result = isc_refcount_init(&pctx->references, 1); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, pctx, sizeof(*pctx)); + return (result); + } + pctx->mctx = mctx; pctx->lctx = lctx; pctx->lexer = NULL; @@ -400,6 +406,7 @@ cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) { pctx->callback = NULL; pctx->callbackarg = NULL; pctx->token.type = isc_tokentype_unknown; + pctx->flags = 0; memset(specials, 0, sizeof(specials)); specials['{'] = 1; @@ -526,17 +533,30 @@ cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer, } void +cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest) { + REQUIRE(src != NULL); + REQUIRE(dest != NULL && *dest == NULL); + isc_refcount_increment(&src->references, NULL); + *dest = src; +} + +void cfg_parser_destroy(cfg_parser_t **pctxp) { cfg_parser_t *pctx = *pctxp; - isc_lex_destroy(&pctx->lexer); - /* - * Cleaning up open_files does not - * close the files; that was already done - * by closing the lexer. - */ - CLEANUP_OBJ(pctx->open_files); - CLEANUP_OBJ(pctx->closed_files); - isc_mem_put(pctx->mctx, pctx, sizeof(*pctx)); + unsigned int refs; + + isc_refcount_decrement(&pctx->references, &refs); + if (refs == 0) { + isc_lex_destroy(&pctx->lexer); + /* + * Cleaning up open_files does not + * close the files; that was already done + * by closing the lexer. + */ + CLEANUP_OBJ(pctx->open_files); + CLEANUP_OBJ(pctx->closed_files); + isc_mem_put(pctx->mctx, pctx, sizeof(*pctx)); + } *pctxp = NULL; } @@ -848,8 +868,8 @@ cfg_obj_asboolean(const cfg_obj_t *obj) { return (obj->value.boolean); } -static isc_result_t -parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) +isc_result_t +cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; isc_boolean_t value; @@ -888,8 +908,8 @@ parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) return (result); } -static void -print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) { +void +cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) { if (obj->value.boolean) cfg_print_chars(pctx, "yes", 3); else @@ -897,7 +917,7 @@ print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) { } cfg_type_t cfg_type_boolean = { - "boolean", parse_boolean, print_boolean, cfg_doc_terminal, + "boolean", cfg_parse_boolean, cfg_print_boolean, cfg_doc_terminal, &cfg_rep_boolean, NULL }; @@ -1132,7 +1152,7 @@ cfg_list_length(const cfg_obj_t *obj, isc_boolean_t recurse) { return (count); } -const cfg_obj_t * +cfg_obj_t * cfg_listelt_value(const cfg_listelt_t *elt) { REQUIRE(elt != NULL); return (elt->obj); @@ -1237,6 +1257,14 @@ cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0) cfg_parser_warning(pctx, 0, "option '%s' is " "not implemented", clause->name); + + if ((clause->flags & CFG_CLAUSEFLAG_NOTCONFIGURED) != 0) { + cfg_parser_warning(pctx, 0, "option '%s' is not " + "configured", clause->name); + result = ISC_R_FAILURE; + goto cleanup; + } + /* * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT * set here - we need to log the *lack* of such an option, @@ -1478,6 +1506,7 @@ static struct flagtext { { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" }, { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" }, { CFG_CLAUSEFLAG_TESTONLY, "test only" }, + { CFG_CLAUSEFLAG_NOTCONFIGURED, "not configured" }, { 0, NULL } }; @@ -2305,6 +2334,7 @@ cfg_obj_line(const cfg_obj_t *obj) { isc_result_t cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { + isc_result_t result; cfg_obj_t *obj; obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t)); @@ -2313,10 +2343,16 @@ cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { obj->type = type; obj->file = current_file(pctx); obj->line = pctx->line; + result = isc_refcount_init(&obj->references, 1); + if (result != ISC_R_SUCCESS) { + isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); + return (result); + } *ret = obj; return (ISC_R_SUCCESS); } + static void map_symtabitem_destroy(char *key, unsigned int type, isc_symvalue_t symval, void *userarg) @@ -2370,11 +2406,25 @@ cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) { void cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) { cfg_obj_t *obj = *objp; - obj->type->rep->free(pctx, obj); - isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); + unsigned int refs; + + isc_refcount_decrement(&obj->references, &refs); + if (refs == 0) { + obj->type->rep->free(pctx, obj); + isc_refcount_destroy(&obj->references); + isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); + } *objp = NULL; } +void +cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest) { + REQUIRE(src != NULL); + REQUIRE(dest != NULL && *dest == NULL); + isc_refcount_increment(&src->references, NULL); + *dest = src; +} + static void free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) { UNUSED(pctx); diff --git a/lib/lwres/api b/lib/lwres/api index fbbf923..94575eb 100644 --- a/lib/lwres/api +++ b/lib/lwres/api @@ -1,3 +1,3 @@ -LIBINTERFACE = 50 -LIBREVISION = 3 +LIBINTERFACE = 80 +LIBREVISION = 0 LIBAGE = 0 diff --git a/lib/lwres/context.c b/lib/lwres/context.c index 1310022..e8f0eda 100644 --- a/lib/lwres/context.c +++ b/lib/lwres/context.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: context.c,v 1.50.332.5 2009-09-01 23:47:05 tbox Exp $ */ +/* $Id: context.c,v 1.55 2009-09-02 23:48:03 tbox Exp $ */ /*! \file context.c lwres_context_create() creates a #lwres_context_t structure for use in diff --git a/lib/lwres/context_p.h b/lib/lwres/context_p.h index 663b1da..0976951 100644 --- a/lib/lwres/context_p.h +++ b/lib/lwres/context_p.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: context_p.h,v 1.17.332.2 2008-12-30 23:46:49 tbox Exp $ */ +/* $Id: context_p.h,v 1.19 2008-12-17 23:47:58 tbox Exp $ */ #ifndef LWRES_CONTEXT_P_H #define LWRES_CONTEXT_P_H 1 diff --git a/lib/lwres/getaddrinfo.c b/lib/lwres/getaddrinfo.c index 665205a..81534fc 100644 --- a/lib/lwres/getaddrinfo.c +++ b/lib/lwres/getaddrinfo.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * This code is derived from software contributed to ISC by @@ -18,7 +18,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: getaddrinfo.c,v 1.52.254.2 2009-03-31 23:47:16 tbox Exp $ */ +/* $Id: getaddrinfo.c,v 1.54 2008-11-25 23:47:23 tbox Exp $ */ /*! \file */ diff --git a/lib/lwres/getipnode.c b/lib/lwres/getipnode.c index b9eadee..bc90c74 100644 --- a/lib/lwres/getipnode.c +++ b/lib/lwres/getipnode.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: getipnode.c,v 1.42.332.5 2009-09-01 23:47:05 tbox Exp $ */ +/* $Id: getipnode.c,v 1.47 2009-09-01 23:47:45 tbox Exp $ */ /*! \file */ diff --git a/lib/lwres/include/lwres/context.h b/lib/lwres/include/lwres/context.h index 46be27a..2421b57 100644 --- a/lib/lwres/include/lwres/context.h +++ b/lib/lwres/include/lwres/context.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: context.h,v 1.21.332.2 2008-12-30 23:46:49 tbox Exp $ */ +/* $Id: context.h,v 1.23 2008-12-17 23:47:58 tbox Exp $ */ #ifndef LWRES_CONTEXT_H #define LWRES_CONTEXT_H 1 diff --git a/lib/lwres/include/lwres/netdb.h.in b/lib/lwres/include/lwres/netdb.h.in index 7531ca3..8eedd27 100644 --- a/lib/lwres/include/lwres/netdb.h.in +++ b/lib/lwres/include/lwres/netdb.h.in @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: netdb.h.in,v 1.39.332.2 2009-01-18 23:47:41 tbox Exp $ */ +/* $Id: netdb.h.in,v 1.41 2009-01-18 23:48:14 tbox Exp $ */ /*! \file */ diff --git a/lib/lwres/lwconfig.c b/lib/lwres/lwconfig.c index 356c106..764ff2a 100644 --- a/lib/lwres/lwconfig.c +++ b/lib/lwres/lwconfig.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lwconfig.c,v 1.46.332.2 2008-12-30 23:46:49 tbox Exp $ */ +/* $Id: lwconfig.c,v 1.48 2008-12-17 23:47:58 tbox Exp $ */ /*! \file */ diff --git a/lib/lwres/man/lwres.3 b/lib/lwres/man/lwres.3 index 77f96b6..c2c0bb6 100644 --- a/lib/lwres/man/lwres.3 +++ b/lib/lwres/man/lwres.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres.3,v 1.28.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres.3,v 1.29 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres.html b/lib/lwres/man/lwres.html index 3844c01..6cfb750 100644 --- a/lib/lwres/man/lwres.html +++ b/lib/lwres/man/lwres.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@
-
+

Name

lwres — introduction to the lightweight resolver library

@@ -32,7 +32,7 @@
#include <lwres/lwres.h>
-

DESCRIPTION

+

DESCRIPTION

The BIND 9 lightweight resolver library is a simple, name service independent stub resolver library. It provides hostname-to-address @@ -47,7 +47,7 @@

-

OVERVIEW

+

OVERVIEW

The lwresd library implements multiple name service APIs. The standard @@ -101,7 +101,7 @@

-

CLIENT-SIDE LOW-LEVEL API CALL FLOW

+

CLIENT-SIDE LOW-LEVEL API CALL FLOW

When a client program wishes to make an lwres request using the native low-level API, it typically performs the following @@ -149,7 +149,7 @@

-

SERVER-SIDE LOW-LEVEL API CALL FLOW

+

SERVER-SIDE LOW-LEVEL API CALL FLOW

When implementing the server side of the lightweight resolver protocol using the lwres library, a sequence of actions like the @@ -191,7 +191,7 @@

-

SEE ALSO

+

SEE ALSO

lwres_gethostent(3), lwres_getipnode(3), diff --git a/lib/lwres/man/lwres_buffer.3 b/lib/lwres/man/lwres_buffer.3 index 89b9b65..0fc5225 100644 --- a/lib/lwres/man/lwres_buffer.3 +++ b/lib/lwres/man/lwres_buffer.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_buffer.3,v 1.26.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_buffer.3,v 1.27 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_buffer.html b/lib/lwres/man/lwres_buffer.html index 7f3934a..b7e034f 100644 --- a/lib/lwres/man/lwres_buffer.html +++ b/lib/lwres/man/lwres_buffer.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@

-
+

Name

lwres_buffer_init, lwres_buffer_invalidate, lwres_buffer_add, lwres_buffer_subtract, lwres_buffer_clear, lwres_buffer_first, lwres_buffer_forward, lwres_buffer_back, lwres_buffer_getuint8, lwres_buffer_putuint8, lwres_buffer_getuint16, lwres_buffer_putuint16, lwres_buffer_getuint32, lwres_buffer_putuint32, lwres_buffer_putmem, lwres_buffer_getmem — lightweight resolver buffer management

@@ -262,7 +262,7 @@ void
-

DESCRIPTION

+

DESCRIPTION

These functions provide bounds checked access to a region of memory where data is being read or written. diff --git a/lib/lwres/man/lwres_config.3 b/lib/lwres/man/lwres_config.3 index 5b8a728..0ea1320 100644 --- a/lib/lwres/man/lwres_config.3 +++ b/lib/lwres/man/lwres_config.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_config.3,v 1.26.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_config.3,v 1.27 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_config.html b/lib/lwres/man/lwres_config.html index 2cee5ef..8c330a3 100644 --- a/lib/lwres/man/lwres_config.html +++ b/lib/lwres/man/lwres_config.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@

-
+

Name

lwres_conf_init, lwres_conf_clear, lwres_conf_parse, lwres_conf_print, lwres_conf_get — lightweight resolver configuration

@@ -90,7 +90,7 @@ lwres_conf_t *
-

DESCRIPTION

+

DESCRIPTION

lwres_conf_init() creates an empty lwres_conf_t @@ -123,7 +123,7 @@ lwres_conf_t *

-

RETURN VALUES

+

RETURN VALUES

lwres_conf_parse() returns LWRES_R_SUCCESS if it successfully read and parsed @@ -142,13 +142,13 @@ lwres_conf_t *

-

SEE ALSO

+

SEE ALSO

stdio(3), resolver(5).

-

FILES

+

FILES

/etc/resolv.conf

diff --git a/lib/lwres/man/lwres_context.3 b/lib/lwres/man/lwres_context.3 index a96a075..fdcaf55 100644 --- a/lib/lwres/man/lwres_context.3 +++ b/lib/lwres/man/lwres_context.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_context.3,v 1.28.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_context.3,v 1.29 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_context.html b/lib/lwres/man/lwres_context.html index d525a4b..50d5d9f 100644 --- a/lib/lwres/man/lwres_context.html +++ b/lib/lwres/man/lwres_context.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@
-
+

Name

lwres_context_create, lwres_context_destroy, lwres_context_nextserial, lwres_context_initserial, lwres_context_freemem, lwres_context_allocmem, lwres_context_sendrecv — lightweight resolver context management

@@ -172,7 +172,7 @@ void *
-

DESCRIPTION

+

DESCRIPTION

lwres_context_create() creates a lwres_context_t structure for use in lightweight resolver operations. It holds a socket and other @@ -258,7 +258,7 @@ void *

-

RETURN VALUES

+

RETURN VALUES

lwres_context_create() returns LWRES_R_NOMEMORY if memory for the struct lwres_context could not be allocated, @@ -283,7 +283,7 @@ void *

-

SEE ALSO

+

SEE ALSO

lwres_conf_init(3), malloc(3), diff --git a/lib/lwres/man/lwres_gabn.3 b/lib/lwres/man/lwres_gabn.3 index 28ea7e1..769c952 100644 --- a/lib/lwres/man/lwres_gabn.3 +++ b/lib/lwres/man/lwres_gabn.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_gabn.3,v 1.27.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_gabn.3,v 1.28 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_gabn.html b/lib/lwres/man/lwres_gabn.html index b69f432..32b5f21 100644 --- a/lib/lwres/man/lwres_gabn.html +++ b/lib/lwres/man/lwres_gabn.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@

-
+

Name

lwres_gabnrequest_render, lwres_gabnresponse_render, lwres_gabnrequest_parse, lwres_gabnresponse_parse, lwres_gabnresponse_free, lwres_gabnrequest_free — lightweight resolver getaddrbyname message handling

@@ -178,7 +178,7 @@ void
-

DESCRIPTION

+

DESCRIPTION

These are low-level routines for creating and parsing lightweight resolver name-to-address lookup request and @@ -278,7 +278,7 @@ typedef struct {

-

RETURN VALUES

+

RETURN VALUES

The getaddrbyname opcode functions lwres_gabnrequest_render(), @@ -316,7 +316,7 @@ typedef struct {

-

SEE ALSO

+

SEE ALSO

lwres_packet(3)

diff --git a/lib/lwres/man/lwres_gai_strerror.3 b/lib/lwres/man/lwres_gai_strerror.3 index 3d80727..2527896 100644 --- a/lib/lwres/man/lwres_gai_strerror.3 +++ b/lib/lwres/man/lwres_gai_strerror.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_gai_strerror.3,v 1.27.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_gai_strerror.3,v 1.28 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_gai_strerror.html b/lib/lwres/man/lwres_gai_strerror.html index 616eebe..9ff330b 100644 --- a/lib/lwres/man/lwres_gai_strerror.html +++ b/lib/lwres/man/lwres_gai_strerror.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@
-
+

Name

lwres_gai_strerror — print suitable error string

@@ -42,7 +42,7 @@ char *
-

DESCRIPTION

+

DESCRIPTION

lwres_gai_strerror() returns an error message corresponding to an error code returned by getaddrinfo(). @@ -110,7 +110,7 @@ char *

-

SEE ALSO

+

SEE ALSO

strerror(3), lwres_getaddrinfo(3), diff --git a/lib/lwres/man/lwres_getaddrinfo.3 b/lib/lwres/man/lwres_getaddrinfo.3 index 2953f3b..cfc4aec 100644 --- a/lib/lwres/man/lwres_getaddrinfo.3 +++ b/lib/lwres/man/lwres_getaddrinfo.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_getaddrinfo.3,v 1.31.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_getaddrinfo.3,v 1.32 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_getaddrinfo.html b/lib/lwres/man/lwres_getaddrinfo.html index 013e878..d367f51 100644 --- a/lib/lwres/man/lwres_getaddrinfo.html +++ b/lib/lwres/man/lwres_getaddrinfo.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@

-
+

Name

lwres_getaddrinfo, lwres_freeaddrinfo — socket address structure to host and service name

@@ -89,7 +89,7 @@ struct addrinfo {

-

DESCRIPTION

+

DESCRIPTION

lwres_getaddrinfo() is used to get a list of IP addresses and port numbers for host hostname and service @@ -283,7 +283,7 @@ struct addrinfo {

-

RETURN VALUES

+

RETURN VALUES

lwres_getaddrinfo() returns zero on success or one of the error codes listed in gai_strerror(3) @@ -294,7 +294,7 @@ struct addrinfo {

-

SEE ALSO

+

SEE ALSO

lwres(3), lwres_getaddrinfo(3), diff --git a/lib/lwres/man/lwres_gethostent.3 b/lib/lwres/man/lwres_gethostent.3 index 35ea1c2..7acc506 100644 --- a/lib/lwres/man/lwres_gethostent.3 +++ b/lib/lwres/man/lwres_gethostent.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_gethostent.3,v 1.29.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_gethostent.3,v 1.30 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_gethostent.html b/lib/lwres/man/lwres_gethostent.html index fd27dcf..fdaa062 100644 --- a/lib/lwres/man/lwres_gethostent.html +++ b/lib/lwres/man/lwres_gethostent.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@

-
+

Name

lwres_gethostbyname, lwres_gethostbyname2, lwres_gethostbyaddr, lwres_gethostent, lwres_sethostent, lwres_endhostent, lwres_gethostbyname_r, lwres_gethostbyaddr_r, lwres_gethostent_r, lwres_sethostent_r, lwres_endhostent_r — lightweight resolver get network host entry

@@ -228,7 +228,7 @@ void
-

DESCRIPTION

+

DESCRIPTION

These functions provide hostname-to-address and address-to-hostname lookups by means of the lightweight resolver. @@ -366,7 +366,7 @@ struct hostent {

-

RETURN VALUES

+

RETURN VALUES

The functions lwres_gethostbyname(), @@ -430,7 +430,7 @@ struct hostent {

-

SEE ALSO

+

SEE ALSO

gethostent(3), lwres_getipnode(3), @@ -439,7 +439,7 @@ struct hostent {

-

BUGS

+

BUGS

lwres_gethostbyname(), lwres_gethostbyname2(), lwres_gethostbyaddr() diff --git a/lib/lwres/man/lwres_getipnode.3 b/lib/lwres/man/lwres_getipnode.3 index b46e78f..40ba59c 100644 --- a/lib/lwres/man/lwres_getipnode.3 +++ b/lib/lwres/man/lwres_getipnode.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_getipnode.3,v 1.28.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_getipnode.3,v 1.29 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_getipnode.html b/lib/lwres/man/lwres_getipnode.html index 20c6d30..9f54cb6 100644 --- a/lib/lwres/man/lwres_getipnode.html +++ b/lib/lwres/man/lwres_getipnode.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@

-
+

Name

lwres_getipnodebyname, lwres_getipnodebyaddr, lwres_freehostent — lightweight resolver nodename / address translation API

@@ -98,7 +98,7 @@ void
-

DESCRIPTION

+

DESCRIPTION

These functions perform thread safe, protocol independent nodename-to-address and address-to-nodename @@ -217,7 +217,7 @@ struct hostent {

-

RETURN VALUES

+

RETURN VALUES

If an error occurs, lwres_getipnodebyname() @@ -261,7 +261,7 @@ struct hostent {

-

SEE ALSO

+

SEE ALSO

RFC2553, lwres(3), diff --git a/lib/lwres/man/lwres_getnameinfo.3 b/lib/lwres/man/lwres_getnameinfo.3 index 3a75efb..5674fb2 100644 --- a/lib/lwres/man/lwres_getnameinfo.3 +++ b/lib/lwres/man/lwres_getnameinfo.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_getnameinfo.3,v 1.29.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_getnameinfo.3,v 1.30 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_getnameinfo.html b/lib/lwres/man/lwres_getnameinfo.html index fb7837f..1048543 100644 --- a/lib/lwres/man/lwres_getnameinfo.html +++ b/lib/lwres/man/lwres_getnameinfo.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@

-
+

Name

lwres_getnameinfo — lightweight resolver socket address structure to hostname and @@ -82,7 +82,7 @@ int

-

DESCRIPTION

+

DESCRIPTION

This function is equivalent to the getnameinfo(3) function defined in RFC2133. @@ -149,13 +149,13 @@ int

-

RETURN VALUES

+

RETURN VALUES

lwres_getnameinfo() returns 0 on success or a non-zero error code if an error occurs.

-

SEE ALSO

+

SEE ALSO

RFC2133, getservbyport(3), lwres(3), @@ -165,7 +165,7 @@ int

-

BUGS

+

BUGS

RFC2133 fails to define what the nonzero return values of getnameinfo(3) diff --git a/lib/lwres/man/lwres_getrrsetbyname.3 b/lib/lwres/man/lwres_getrrsetbyname.3 index c804e11..2aa1a9c 100644 --- a/lib/lwres/man/lwres_getrrsetbyname.3 +++ b/lib/lwres/man/lwres_getrrsetbyname.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_getrrsetbyname.3,v 1.25.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_getrrsetbyname.3,v 1.26 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_getrrsetbyname.html b/lib/lwres/man/lwres_getrrsetbyname.html index 9d9dc04..3a7fb9f 100644 --- a/lib/lwres/man/lwres_getrrsetbyname.html +++ b/lib/lwres/man/lwres_getrrsetbyname.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@

-
+

Name

lwres_getrrsetbyname, lwres_freerrset — retrieve DNS records

@@ -102,7 +102,7 @@ struct rrsetinfo {

-

DESCRIPTION

+

DESCRIPTION

lwres_getrrsetbyname() gets a set of resource records associated with a hostname, class, @@ -150,7 +150,7 @@ struct rrsetinfo {

-

RETURN VALUES

+

RETURN VALUES

lwres_getrrsetbyname() returns zero on success, and one of the following error codes if an error occurred: @@ -184,7 +184,7 @@ struct rrsetinfo {

-

SEE ALSO

+

SEE ALSO

lwres(3).

diff --git a/lib/lwres/man/lwres_gnba.3 b/lib/lwres/man/lwres_gnba.3 index b34fc05..ad9d627 100644 --- a/lib/lwres/man/lwres_gnba.3 +++ b/lib/lwres/man/lwres_gnba.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_gnba.3,v 1.27.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_gnba.3,v 1.28 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_gnba.html b/lib/lwres/man/lwres_gnba.html index 158f4d0..8c7691e 100644 --- a/lib/lwres/man/lwres_gnba.html +++ b/lib/lwres/man/lwres_gnba.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@
-
+

Name

lwres_gnbarequest_render, lwres_gnbaresponse_render, lwres_gnbarequest_parse, lwres_gnbaresponse_parse, lwres_gnbaresponse_free, lwres_gnbarequest_free — lightweight resolver getnamebyaddress message handling

@@ -183,7 +183,7 @@ void
-

DESCRIPTION

+

DESCRIPTION

These are low-level routines for creating and parsing lightweight resolver address-to-name lookup request and @@ -270,7 +270,7 @@ typedef struct {

-

RETURN VALUES

+

RETURN VALUES

The getnamebyaddr opcode functions lwres_gnbarequest_render(), @@ -308,7 +308,7 @@ typedef struct {

-

SEE ALSO

+

SEE ALSO

lwres_packet(3).

diff --git a/lib/lwres/man/lwres_hstrerror.3 b/lib/lwres/man/lwres_hstrerror.3 index f65ba54..b9d5316 100644 --- a/lib/lwres/man/lwres_hstrerror.3 +++ b/lib/lwres/man/lwres_hstrerror.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_hstrerror.3,v 1.27.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_hstrerror.3,v 1.28 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_hstrerror.html b/lib/lwres/man/lwres_hstrerror.html index d5d25ec..df1c425 100644 --- a/lib/lwres/man/lwres_hstrerror.html +++ b/lib/lwres/man/lwres_hstrerror.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@
-
+

Name

lwres_herror, lwres_hstrerror — lightweight resolver error message generation

@@ -50,7 +50,7 @@ const char *
-

DESCRIPTION

+

DESCRIPTION

lwres_herror() prints the string s on stderr followed by the string generated by @@ -84,7 +84,7 @@ const char *

-

RETURN VALUES

+

RETURN VALUES

The string Unknown resolver error is returned by lwres_hstrerror() @@ -94,7 +94,7 @@ const char *

-

SEE ALSO

+

SEE ALSO

herror(3), lwres_hstrerror(3). diff --git a/lib/lwres/man/lwres_inetntop.3 b/lib/lwres/man/lwres_inetntop.3 index 6bd063a..be85906 100644 --- a/lib/lwres/man/lwres_inetntop.3 +++ b/lib/lwres/man/lwres_inetntop.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_inetntop.3,v 1.26.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_inetntop.3,v 1.27 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_inetntop.html b/lib/lwres/man/lwres_inetntop.html index 8467e4b..f0ea41a 100644 --- a/lib/lwres/man/lwres_inetntop.html +++ b/lib/lwres/man/lwres_inetntop.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@

-
+

Name

lwres_net_ntop — lightweight resolver IP address presentation

@@ -62,7 +62,7 @@ const char *
-

DESCRIPTION

+

DESCRIPTION

lwres_net_ntop() converts an IP address of protocol family af — IPv4 or IPv6 — at @@ -80,7 +80,7 @@ const char *

-

RETURN VALUES

+

RETURN VALUES

If successful, the function returns dst: a pointer to a string containing the presentation format of the @@ -93,7 +93,7 @@ const char *

-

SEE ALSO

+

SEE ALSO

RFC1884, inet_ntop(3), errno(3). diff --git a/lib/lwres/man/lwres_noop.3 b/lib/lwres/man/lwres_noop.3 index fd05e7e..3be40b2 100644 --- a/lib/lwres/man/lwres_noop.3 +++ b/lib/lwres/man/lwres_noop.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_noop.3,v 1.28.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_noop.3,v 1.29 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_noop.html b/lib/lwres/man/lwres_noop.html index 4a94836..8f9d402 100644 --- a/lib/lwres/man/lwres_noop.html +++ b/lib/lwres/man/lwres_noop.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@

-
+

Name

lwres_nooprequest_render, lwres_noopresponse_render, lwres_nooprequest_parse, lwres_noopresponse_parse, lwres_noopresponse_free, lwres_nooprequest_free — lightweight resolver no-op message handling

@@ -179,7 +179,7 @@ void
-

DESCRIPTION

+

DESCRIPTION

These are low-level routines for creating and parsing lightweight resolver no-op request and response messages. @@ -270,7 +270,7 @@ typedef struct {

-

RETURN VALUES

+

RETURN VALUES

The no-op opcode functions lwres_nooprequest_render(), @@ -309,7 +309,7 @@ typedef struct {

-

SEE ALSO

+

SEE ALSO

lwres_packet(3)

diff --git a/lib/lwres/man/lwres_packet.3 b/lib/lwres/man/lwres_packet.3 index 5c096b5..ad4a82c 100644 --- a/lib/lwres/man/lwres_packet.3 +++ b/lib/lwres/man/lwres_packet.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_packet.3,v 1.29.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_packet.3,v 1.30 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_packet.html b/lib/lwres/man/lwres_packet.html index 096b4bb..84eafc1 100644 --- a/lib/lwres/man/lwres_packet.html +++ b/lib/lwres/man/lwres_packet.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@
-
+

Name

lwres_lwpacket_renderheader, lwres_lwpacket_parseheader — lightweight resolver packet handling functions

@@ -66,7 +66,7 @@ lwres_result_t
-

DESCRIPTION

+

DESCRIPTION

These functions rely on a struct lwres_lwpacket @@ -219,7 +219,7 @@ struct lwres_lwpacket {

-

RETURN VALUES

+

RETURN VALUES

Successful calls to lwres_lwpacket_renderheader() and diff --git a/lib/lwres/man/lwres_resutil.3 b/lib/lwres/man/lwres_resutil.3 index 6e17797..04cad4e 100644 --- a/lib/lwres/man/lwres_resutil.3 +++ b/lib/lwres/man/lwres_resutil.3 @@ -13,7 +13,7 @@ .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR .\" PERFORMANCE OF THIS SOFTWARE. .\" -.\" $Id: lwres_resutil.3,v 1.28.418.1 2009-07-11 01:55:21 tbox Exp $ +.\" $Id: lwres_resutil.3,v 1.29 2009-07-11 01:12:46 tbox Exp $ .\" .hy 0 .ad l diff --git a/lib/lwres/man/lwres_resutil.html b/lib/lwres/man/lwres_resutil.html index 1d2aa76..b4de764 100644 --- a/lib/lwres/man/lwres_resutil.html +++ b/lib/lwres/man/lwres_resutil.html @@ -14,7 +14,7 @@ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. --> - + @@ -22,7 +22,7 @@

-
+

Name

lwres_string_parse, lwres_addr_parse, lwres_getaddrsbyname, lwres_getnamebyaddr — lightweight resolver utility functions

@@ -134,7 +134,7 @@ lwres_result_t
-

DESCRIPTION

+

DESCRIPTION

lwres_string_parse() retrieves a DNS-encoded string starting the current pointer of lightweight resolver buffer b: i.e. @@ -210,7 +210,7 @@ typedef struct {

-

RETURN VALUES

+

RETURN VALUES

Successful calls to lwres_string_parse() @@ -248,7 +248,7 @@ typedef struct {

-

SEE ALSO

+

SEE ALSO

lwres_buffer(3), lwres_gabn(3). diff --git a/lib/lwres/print_p.h b/lib/lwres/print_p.h index e2f6ad6..ed71535 100644 --- a/lib/lwres/print_p.h +++ b/lib/lwres/print_p.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: print_p.h,v 1.4.332.2 2010-08-16 23:45:48 tbox Exp $ */ +/* $Id: print_p.h,v 1.6 2010-08-16 23:46:52 tbox Exp $ */ #ifndef LWRES_PRINT_P_H #define LWRES_PRINT_P_H 1 -- cgit v1.1